use std::future::Future;
use tower::Service;
use crate::{HttpBody, HttpResponse};
pub trait HttpClientExt: Clone {
fn execute<B>(
&self,
request: http::Request<B>,
) -> impl Future<Output = crate::Result<HttpResponse>>
where
B: Into<HttpBody>;
}
impl<S> HttpClientExt for S
where
S: Service<http::Request<HttpBody>, Response = HttpResponse, Error = crate::Error>
+ Clone
+ Send
+ 'static,
S::Future: Send + 'static,
S::Error: 'static,
{
fn execute<B>(
&self,
request: http::Request<B>,
) -> impl Future<Output = crate::Result<HttpResponse>>
where
B: Into<HttpBody>,
{
let request = request.map(Into::into);
self.clone().call(request)
}
}
#[cfg(test)]
mod tests {
use http::{header::USER_AGENT, HeaderValue};
use reqwest::Client;
use tower::ServiceBuilder;
use tower_http::ServiceBuilderExt;
use wiremock::{
matchers::{method, path},
Mock, MockServer, ResponseTemplate,
};
use crate::{util::HttpClientExt, HttpClientLayer};
#[tokio::test]
async fn test_reqwest_http_client_util() -> anyhow::Result<()> {
let mock_server = MockServer::start().await;
let mock_uri = mock_server.uri();
Mock::given(method("GET"))
.and(path("/hello"))
.respond_with(ResponseTemplate::new(200))
.mount(&mock_server)
.await;
let client = ServiceBuilder::new()
.override_response_header(USER_AGENT, HeaderValue::from_static("tower-reqwest"))
.layer(HttpClientLayer)
.service(Client::new());
let response = client
.execute(
http::request::Builder::new()
.method(http::Method::GET)
.uri(format!("{mock_uri}/hello"))
.body("")?,
)
.await?;
assert!(response.status().is_success());
assert_eq!(
response.headers().get(USER_AGENT).unwrap(),
HeaderValue::from_static("tower-reqwest")
);
Ok(())
}
}