1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
use crate::{Request, ResponseTemplate};
/// Anything that implements `Respond` can be used to reply to an incoming request when a
/// [`Mock`] is activated.
///
/// ## Fixed responses
///
/// The simplest `Respond` is [`ResponseTemplate`]: no matter the request, it will
/// always return itself.
///
/// ```rust
/// use wiremock::{MockServer, Mock, ResponseTemplate};
/// use wiremock::matchers::method;
///
/// #[async_std::main]
/// async fn main() {
/// // Arrange
/// let mock_server = MockServer::start().await;
/// let correlation_id = "1311db4f-fe65-4cb2-b514-1bb47f781aa7";
/// let template = ResponseTemplate::new(200).insert_header(
/// "X-Correlation-ID",
/// correlation_id
/// );
/// Mock::given(method("GET"))
/// .respond_with(template)
/// .mount(&mock_server)
/// .await;
///
/// // Act
/// let response = surf::get(&mock_server.uri())
/// .await
/// .unwrap();
///
/// // Assert
/// assert_eq!(response.status(), 200);
/// assert_eq!(response.header("X-Correlation-ID").unwrap().as_str(), correlation_id);
/// }
/// ```
///
/// ## Dynamic responses
///
/// You can use `Respond`, though, to implement responses that depend on the data in
/// the request matched by a [`Mock`].
///
/// Functions from `Request` to `ResponseTemplate` implement `Respond`, so for simple cases you
/// can use a closure to build a response dynamically, for instance to echo the request body back:
///
/// ```rust
/// use wiremock::{Match, MockServer, Mock, Request, ResponseTemplate};
/// use wiremock::matchers::path;
///
/// #[async_std::main]
/// async fn main() {
/// let mock_server = MockServer::start().await;
/// let body = "Mock Server!".to_string();
///
/// Mock::given(path("/echo"))
/// .respond_with(|req: &Request| {
/// let body_string = String::from_utf8(req.body.clone()).unwrap();
/// ResponseTemplate::new(200).set_body_string(body_string)
/// })
/// .mount(&mock_server)
/// .await;
///
/// let mut response = surf::post(format!("{}/echo", &mock_server.uri()))
/// .body(body.clone())
/// .await
/// .unwrap();
/// assert_eq!(response.status(), 200);
/// assert_eq!(response.body_string().await.unwrap(), body);
/// }
/// ```
///
/// For more complex cases you may want to implement `Respond` yourself. As an example, this is a
/// `Respond` that propagates back a request header in the response:
///
/// ```rust
/// use http_types::headers::HeaderName;
/// use wiremock::{Match, MockServer, Mock, Request, ResponseTemplate, Respond};
/// use wiremock::matchers::path;
/// use std::convert::TryInto;
/// use std::str::FromStr;
///
/// /// Responds using the specified `ResponseTemplate`, but it dynamically populates the
/// /// `X-Correlation-Id` header from the request data.
/// pub struct CorrelationIdResponder(pub ResponseTemplate);
///
/// impl Respond for CorrelationIdResponder {
/// fn respond(&self, request: &Request) -> ResponseTemplate {
/// let mut response_template = self.0.clone();
/// let header_name = HeaderName::from_str("X-Correlation-Id").unwrap();
/// if let Some(correlation_id) = request.headers.get(&header_name) {
/// response_template = response_template.insert_header(
/// header_name,
/// correlation_id.last().to_owned()
/// );
/// }
/// response_template
/// }
/// }
///
/// #[async_std::main]
/// async fn main() {
/// // Arrange
/// let mock_server = MockServer::start().await;
/// let correlation_id = "1241-1245-1548-4567";
///
/// Mock::given(path("/hello"))
/// .respond_with(CorrelationIdResponder(ResponseTemplate::new(200)))
/// .mount(&mock_server)
/// .await;
///
/// let response = surf::get(format!("{}/hello", &mock_server.uri()))
/// .header("X-Correlation-Id", correlation_id)
/// .await
/// .unwrap();
/// assert_eq!(response.status(), 200);
/// assert_eq!(response.header("X-Correlation-Id").unwrap().as_str(), correlation_id);
/// }
/// ```
///
/// [`Mock`]: crate::Mock
/// [`ResponseTemplate`]: crate::ResponseTemplate
pub trait Respond: Send + Sync {
/// Given a reference to a [`Request`] return a [`ResponseTemplate`] that will be used
/// by the [`MockServer`] as blueprint for the response returned to the client.
///
/// [`Request`]: crate::Request
/// [`MockServer`]: crate::MockServer
/// [`ResponseTemplate`]: crate::ResponseTemplate
fn respond(&self, request: &Request) -> ResponseTemplate;
}
/// A `ResponseTemplate` is the simplest `Respond` implementation: it returns a clone of itself
/// no matter what the incoming request contains!
impl Respond for ResponseTemplate {
fn respond(&self, _request: &Request) -> ResponseTemplate {
self.clone()
}
}
impl<F> Respond for F
where
F: Send + Sync + Fn(&Request) -> ResponseTemplate,
{
fn respond(&self, request: &Request) -> ResponseTemplate {
(self)(request)
}
}