tower_http_client/client/
service_ext.rs

1use std::future::Future;
2
3use http::{Method, Uri};
4use tower_service::Service;
5
6use super::{ClientRequest, IntoUri, client_request::ClientRequestBuilder};
7
8/// An extension trait for Tower HTTP services with the typical client methods.
9///
10/// Essentially, this trait adds methods similar to those in [`reqwest::Client`] one.
11///
12/// # Examples
13///
14/// Creating a client and reading the response body using this trait.
15///
16#[doc = include_utils::include_md!("README.md:example")]
17///
18/// [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html
19pub trait ServiceExt<ReqBody, RespBody, Err>: Sized {
20    /// Executes an HTTP request.
21    fn execute<R>(
22        &mut self,
23        request: http::Request<R>,
24    ) -> impl Future<Output = Result<http::Response<RespBody>, Err>>
25    where
26        ReqBody: From<R>;
27
28    /// Starts building a request with the given method and URI.
29    fn request<U>(
30        &mut self,
31        method: Method,
32        uri: U,
33    ) -> ClientRequestBuilder<'_, Self, Err, RespBody>
34    where
35        U: IntoUri,
36        Uri: TryFrom<U::TryInto>,
37        <Uri as TryFrom<U::TryInto>>::Error: Into<http::Error>,
38    {
39        ClientRequest::builder(self).method(method).uri(uri)
40    }
41
42    /// Convenience method to make a `GET` request to a given URL.
43    fn get<U>(&mut self, uri: U) -> ClientRequestBuilder<'_, Self, Err, RespBody>
44    where
45        U: IntoUri,
46        Uri: TryFrom<U::TryInto>,
47        <Uri as TryFrom<U::TryInto>>::Error: Into<http::Error>,
48    {
49        self.request(Method::GET, uri)
50    }
51
52    /// Convenience method to make a `PUT` request to a given URL.
53    fn put<U>(&mut self, uri: U) -> ClientRequestBuilder<'_, Self, Err, RespBody>
54    where
55        U: IntoUri,
56        Uri: TryFrom<U::TryInto>,
57        <Uri as TryFrom<U::TryInto>>::Error: Into<http::Error>,
58    {
59        self.request(Method::PUT, uri)
60    }
61
62    /// Convenience method to make a `POST` request to a given URL.
63    fn post<U>(&mut self, uri: U) -> ClientRequestBuilder<'_, Self, Err, RespBody>
64    where
65        U: IntoUri,
66        Uri: TryFrom<U::TryInto>,
67        <Uri as TryFrom<U::TryInto>>::Error: Into<http::Error>,
68    {
69        self.request(Method::POST, uri)
70    }
71
72    /// Convenience method to make a `PATCH` request to a given URL.
73    fn patch<U>(&mut self, uri: U) -> ClientRequestBuilder<'_, Self, Err, RespBody>
74    where
75        U: IntoUri,
76        Uri: TryFrom<U::TryInto>,
77        <Uri as TryFrom<U::TryInto>>::Error: Into<http::Error>,
78    {
79        self.request(Method::PATCH, uri)
80    }
81
82    /// Convenience method to make a `DELETE` request to a given URL.
83    fn delete<U>(&mut self, uri: U) -> ClientRequestBuilder<'_, Self, Err, RespBody>
84    where
85        U: IntoUri,
86        Uri: TryFrom<U::TryInto>,
87        <Uri as TryFrom<U::TryInto>>::Error: Into<http::Error>,
88    {
89        self.request(Method::DELETE, uri)
90    }
91
92    /// Convenience method to make a `HEAD` request to a given URL.
93    fn head<U>(&mut self, uri: U) -> ClientRequestBuilder<'_, Self, Err, RespBody>
94    where
95        U: IntoUri,
96        Uri: TryFrom<U::TryInto>,
97        <Uri as TryFrom<U::TryInto>>::Error: Into<http::Error>,
98    {
99        self.request(Method::HEAD, uri)
100    }
101}
102
103impl<S, ReqBody, RespBody, Err> ServiceExt<ReqBody, RespBody, Err> for S
104where
105    S: Service<http::Request<ReqBody>, Response = http::Response<RespBody>, Error = Err>,
106    S::Future: Send + 'static,
107    S::Error: 'static,
108{
109    async fn execute<R>(
110        &mut self,
111        request: http::Request<R>,
112    ) -> Result<http::Response<RespBody>, Err>
113    where
114        ReqBody: From<R>,
115    {
116        // Wait until service will be ready to executing requests. It's important for buffered services.
117        futures_util::future::poll_fn(|ctx| self.poll_ready(ctx)).await?;
118        // And then execute the given request.
119        self.call(request.map(ReqBody::from)).await
120    }
121}