tower_async_service/lib.rs
1#![warn(
2 missing_debug_implementations,
3 missing_docs,
4 rust_2018_idioms,
5 unreachable_pub
6)]
7#![forbid(unsafe_code)]
8// `rustdoc::broken_intra_doc_links` is checked on CI
9
10//! Definition of the core `Service` trait to Tower
11//!
12//! The [`Service`] trait provides the necessary abstractions for defining
13//! request / response clients and servers. It is simple but powerful and is
14//! used as the foundation for the rest of Tower.
15
16/// An asynchronous function from a `Request` to a `Response`.
17///
18/// The `Service` trait is a simplified interface making it easy to write
19/// network applications in a modular and reusable way, decoupled from the
20/// underlying protocol. It is one of Tower's fundamental abstractions.
21///
22/// # Functional
23///
24/// A `Service` is a function of a `Request`. It immediately returns a
25/// `Future` representing the eventual completion of processing the
26/// request. The actual request processing may happen at any time in the
27/// future, on any thread or executor. The processing may depend on calling
28/// other services. At some point in the future, the processing will complete,
29/// and the `Future` will resolve to a response or error.
30///
31/// At a high level, the `Service::call` function represents an RPC request. The
32/// `Service` value can be a server or a client.
33///
34/// # Server
35///
36/// An RPC server *implements* the `Service` trait. Requests received by the
37/// server over the network are deserialized and then passed as an argument to the
38/// server value. The returned response is sent back over the network.
39///
40/// As an example, here is how an HTTP request is processed by a server:
41///
42/// ```rust
43/// # use tower_async_service::Service;
44/// use http::{Request, Response, StatusCode};
45///
46/// struct HelloWorld;
47///
48/// impl Service<Request<Vec<u8>>> for HelloWorld {
49/// type Response = Response<Vec<u8>>;
50/// type Error = http::Error;
51///
52/// async fn call(&self, req: Request<Vec<u8>>) -> Result<Self::Response, Self::Error> {
53/// // create the body
54/// let body: Vec<u8> = "hello, world!\n"
55/// .as_bytes()
56/// .to_owned();
57/// // Create the HTTP response
58/// let resp = Response::builder()
59/// .status(StatusCode::OK)
60/// .body(body)
61/// .expect("Unable to create `http::Response`");
62/// // Return the response
63/// Ok(resp)
64/// }
65/// }
66/// ```
67///
68/// # Client
69///
70/// A client consumes a service by using a `Service` value. The client may
71/// issue requests by invoking `call` and passing the request as an argument.
72/// It then receives the response by waiting for the returned future.
73///
74/// As an example, here is how a Redis request would be issued:
75///
76/// ```rust,ignore
77/// let client = redis::Client::new()
78/// .connect("127.0.0.1:6379".parse().unwrap())
79/// .unwrap();
80///
81/// let resp = client.call(Cmd::set("foo", "this is the value of foo")).await?;
82///
83/// // Wait for the future to resolve
84/// println!("Redis response: {:?}", resp);
85/// ```
86///
87/// # Middleware / Layer
88///
89/// More often than not, all the pieces needed for writing robust, scalable
90/// network applications are the same no matter the underlying protocol. By
91/// unifying the API for both clients and servers in a protocol agnostic way,
92/// it is possible to write middleware that provide these pieces in a
93/// reusable way.
94///
95/// Take timeouts as an example:
96///
97/// ```rust
98/// use tower_async_service::Service;
99/// use tower_async_layer::Layer;
100/// use futures::FutureExt;
101/// use std::future::Future;
102/// use std::task::{Context, Poll};
103/// use std::time::Duration;
104/// use std::pin::Pin;
105/// use std::fmt;
106/// use std::error::Error;
107///
108/// // Our timeout service, which wraps another service and
109/// // adds a timeout to its response future.
110/// pub struct Timeout<T> {
111/// inner: T,
112/// timeout: Duration,
113/// }
114///
115/// impl<T> Timeout<T> {
116/// pub fn new(inner: T, timeout: Duration) -> Timeout<T> {
117/// Timeout {
118/// inner,
119/// timeout
120/// }
121/// }
122/// }
123///
124/// // The error returned if processing a request timed out
125/// #[derive(Debug)]
126/// pub struct Expired;
127///
128/// impl fmt::Display for Expired {
129/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130/// write!(f, "expired")
131/// }
132/// }
133///
134/// impl Error for Expired {}
135///
136/// // We can implement `Service` for `Timeout<T>` if `T` is a `Service`
137/// impl<T, Request> Service<Request> for Timeout<T>
138/// where
139/// T: Service<Request>,
140/// T::Error: Into<Box<dyn Error + Send + Sync>>,
141/// T::Response: 'static,
142/// {
143/// // `Timeout` doesn't modify the response type, so we use `T`'s response type
144/// type Response = T::Response;
145/// // Errors may be either `Expired` if the timeout expired, or the inner service's
146/// // `Error` type. Therefore, we return a boxed `dyn Error + Send + Sync` trait object to erase
147/// // the error's type.
148/// type Error = Box<dyn Error + Send + Sync>;
149///
150/// async fn call(&self, req: Request) -> Result<Self::Response, Self::Error> {
151/// tokio::select! {
152/// res = self.inner.call(req) => {
153/// res.map_err(|err| err.into())
154/// },
155/// _ = tokio::time::sleep(self.timeout) => {
156/// Err(Box::new(Expired) as Box<dyn Error + Send + Sync>)
157/// },
158/// }
159/// }
160/// }
161///
162/// // A layer for wrapping services in `Timeout`
163/// pub struct TimeoutLayer(Duration);
164///
165/// impl TimeoutLayer {
166/// pub fn new(delay: Duration) -> Self {
167/// TimeoutLayer(delay)
168/// }
169/// }
170///
171/// impl<S> Layer<S> for TimeoutLayer {
172/// type Service = Timeout<S>;
173///
174/// fn layer(&self, service: S) -> Timeout<S> {
175/// Timeout::new(service, self.0)
176/// }
177/// }
178/// ```
179///
180/// The above timeout implementation is decoupled from the underlying protocol
181/// and is also decoupled from client or server concerns. In other words, the
182/// same timeout middleware could be used in either a client or a server.
183///
184/// # Backpressure
185///
186/// There is no explicit support for Backpressure in the service.
187/// This can be achieved by having middleware at the front which
188/// implements backpressure and propagates it through the service
189///
190/// Or one can also implement it in the location where this
191/// service gets created.
192///
193/// The original tower library had a `poll_ready` method which
194/// was used to implement backpressure. This was removed in this fork in
195/// favor of the above approach.
196pub trait Service<Request> {
197 /// Responses given by the service.
198 type Response;
199
200 /// Errors produced by the service.
201 type Error;
202
203 /// Process the request and return the response asynchronously.
204 #[must_use = "futures do nothing unless you `.await` or poll them"]
205 fn call(
206 &self,
207 req: Request,
208 ) -> impl std::future::Future<Output = Result<Self::Response, Self::Error>>;
209}
210
211impl<'a, S, Request> Service<Request> for &'a mut S
212where
213 S: Service<Request> + 'a,
214{
215 type Response = S::Response;
216 type Error = S::Error;
217
218 fn call(
219 &self,
220 request: Request,
221 ) -> impl std::future::Future<
222 Output = Result<
223 <&'a mut S as Service<Request>>::Response,
224 <&'a mut S as Service<Request>>::Error,
225 >,
226 > {
227 (**self).call(request)
228 }
229}
230
231impl<S, Request> Service<Request> for Box<S>
232where
233 S: Service<Request> + ?Sized,
234{
235 type Response = S::Response;
236 type Error = S::Error;
237
238 fn call(
239 &self,
240 request: Request,
241 ) -> impl std::future::Future<Output = Result<Self::Response, Self::Error>> {
242 (**self).call(request)
243 }
244}