Trait tower::util::ServiceExt
source · [−]pub trait ServiceExt<Request>: Service<Request> {
Show 14 methods
fn ready(&mut self) -> Ready<'_, Self, Request>ⓘNotable traits for Ready<'a, T, Request>impl<'a, T, Request> Future for Ready<'a, T, Request>where
T: Service<Request>, type Output = Result<&'a mut T, T::Error>;
where
Self: Sized,
{ ... }
fn ready_and(&mut self) -> ReadyAnd<'_, Self, Request>
where
Self: Sized,
{ ... }
fn ready_oneshot(self) -> ReadyOneshot<Self, Request>ⓘNotable traits for ReadyOneshot<T, Request>impl<T, Request> Future for ReadyOneshot<T, Request>where
T: Service<Request>, type Output = Result<T, T::Error>;
where
Self: Sized,
{ ... }
fn oneshot(self, req: Request) -> Oneshot<Self, Request>ⓘNotable traits for Oneshot<S, Req>impl<S, Req> Future for Oneshot<S, Req>where
S: Service<Req>, type Output = Result<S::Response, S::Error>;
where
Self: Sized,
{ ... }
fn call_all<S>(self, reqs: S) -> CallAll<Self, S>
where
Self: Sized,
Self::Error: Into<BoxError>,
S: Stream<Item = Request>,
{ ... }
fn and_then<F>(self, f: F) -> AndThen<Self, F>
where
Self: Sized,
F: Clone,
{ ... }
fn map_response<F, Response>(self, f: F) -> MapResponse<Self, F>
where
Self: Sized,
F: FnOnce(Self::Response) -> Response + Clone,
{ ... }
fn map_err<F, Error>(self, f: F) -> MapErr<Self, F>
where
Self: Sized,
F: FnOnce(Self::Error) -> Error + Clone,
{ ... }
fn map_result<F, Response, Error>(self, f: F) -> MapResult<Self, F>
where
Self: Sized,
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Result<Response, Error> + Clone,
{ ... }
fn map_request<F, NewRequest>(self, f: F) -> MapRequest<Self, F>
where
Self: Sized,
F: FnMut(NewRequest) -> Request,
{ ... }
fn then<F, Response, Error, Fut>(self, f: F) -> Then<Self, F>
where
Self: Sized,
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Fut + Clone,
Fut: Future<Output = Result<Response, Error>>,
{ ... }
fn map_future<F, Fut, Response, Error>(self, f: F) -> MapFuture<Self, F>
where
Self: Sized,
F: FnMut(Self::Future) -> Fut,
Error: From<Self::Error>,
Fut: Future<Output = Result<Response, Error>>,
{ ... }
fn boxed(self) -> BoxService<Request, Self::Response, Self::Error>
where
Self: Sized + Send + 'static,
Self::Future: Send + 'static,
{ ... }
fn boxed_clone(
self
) -> BoxCloneService<Request, Self::Response, Self::Error>
where
Self: Clone + Sized + Send + 'static,
Self::Future: Send + 'static,
{ ... }
}
Expand description
An extension trait for Service
s that provides a variety of convenient
adapters
Provided Methods
sourcefn ready(&mut self) -> Ready<'_, Self, Request>ⓘNotable traits for Ready<'a, T, Request>impl<'a, T, Request> Future for Ready<'a, T, Request>where
T: Service<Request>, type Output = Result<&'a mut T, T::Error>;
where
Self: Sized,
fn ready(&mut self) -> Ready<'_, Self, Request>ⓘNotable traits for Ready<'a, T, Request>impl<'a, T, Request> Future for Ready<'a, T, Request>where
T: Service<Request>, type Output = Result<&'a mut T, T::Error>;
where
Self: Sized,
T: Service<Request>, type Output = Result<&'a mut T, T::Error>;
Yields a mutable reference to the service when it is ready to accept a request.
sourcefn ready_and(&mut self) -> ReadyAnd<'_, Self, Request>where
Self: Sized,
fn ready_and(&mut self) -> ReadyAnd<'_, Self, Request>where
Self: Sized,
ServiceExt::ready
method insteadYields a mutable reference to the service when it is ready to accept a request.
sourcefn ready_oneshot(self) -> ReadyOneshot<Self, Request>ⓘNotable traits for ReadyOneshot<T, Request>impl<T, Request> Future for ReadyOneshot<T, Request>where
T: Service<Request>, type Output = Result<T, T::Error>;
where
Self: Sized,
fn ready_oneshot(self) -> ReadyOneshot<Self, Request>ⓘNotable traits for ReadyOneshot<T, Request>impl<T, Request> Future for ReadyOneshot<T, Request>where
T: Service<Request>, type Output = Result<T, T::Error>;
where
Self: Sized,
T: Service<Request>, type Output = Result<T, T::Error>;
Yields the service when it is ready to accept a request.
sourcefn oneshot(self, req: Request) -> Oneshot<Self, Request>ⓘNotable traits for Oneshot<S, Req>impl<S, Req> Future for Oneshot<S, Req>where
S: Service<Req>, type Output = Result<S::Response, S::Error>;
where
Self: Sized,
fn oneshot(self, req: Request) -> Oneshot<Self, Request>ⓘNotable traits for Oneshot<S, Req>impl<S, Req> Future for Oneshot<S, Req>where
S: Service<Req>, type Output = Result<S::Response, S::Error>;
where
Self: Sized,
S: Service<Req>, type Output = Result<S::Response, S::Error>;
Consume this Service
, calling with the providing request once it is ready.
sourcefn call_all<S>(self, reqs: S) -> CallAll<Self, S>where
Self: Sized,
Self::Error: Into<BoxError>,
S: Stream<Item = Request>,
fn call_all<S>(self, reqs: S) -> CallAll<Self, S>where
Self: Sized,
Self::Error: Into<BoxError>,
S: Stream<Item = Request>,
Process all requests from the given Stream
, and produce a Stream
of their responses.
This is essentially Stream<Item = Request>
+ Self
=> Stream<Item = Response>
. See the documentation for CallAll
for
details.
sourcefn and_then<F>(self, f: F) -> AndThen<Self, F>where
Self: Sized,
F: Clone,
fn and_then<F>(self, f: F) -> AndThen<Self, F>where
Self: Sized,
F: Clone,
Executes a new future after this service’s future resolves. This does
not alter the behaviour of the poll_ready
method.
This method can be used to change the Response
type of the service
into a different type. You can use this method to chain along a computation once the
service’s response has been resolved.
Example
// A service returning Result<Record, _>
let service = DatabaseService::new("127.0.0.1:8080");
// Map the response into a new response
let mut new_service = service.and_then(|record: Record| async move {
let name = record.name;
avatar_lookup(name).await
});
// Call the new service
let id = 13;
let avatar = new_service.call(id).await.unwrap();
sourcefn map_response<F, Response>(self, f: F) -> MapResponse<Self, F>where
Self: Sized,
F: FnOnce(Self::Response) -> Response + Clone,
fn map_response<F, Response>(self, f: F) -> MapResponse<Self, F>where
Self: Sized,
F: FnOnce(Self::Response) -> Response + Clone,
Maps this service’s response value to a different value. This does not
alter the behaviour of the poll_ready
method.
This method can be used to change the Response
type of the service
into a different type. It is similar to the [Result::map
]
method. You can use this method to chain along a computation once the
service’s response has been resolved.
Example
// A service returning Result<Record, _>
let service = DatabaseService::new("127.0.0.1:8080");
// Map the response into a new response
let mut new_service = service.map_response(|record| record.name);
// Call the new service
let id = 13;
let name = new_service
.ready()
.await?
.call(id)
.await?;
sourcefn map_err<F, Error>(self, f: F) -> MapErr<Self, F>where
Self: Sized,
F: FnOnce(Self::Error) -> Error + Clone,
fn map_err<F, Error>(self, f: F) -> MapErr<Self, F>where
Self: Sized,
F: FnOnce(Self::Error) -> Error + Clone,
Maps this service’s error value to a different value. This does not
alter the behaviour of the poll_ready
method.
This method can be used to change the Error
type of the service
into a different type. It is similar to the [Result::map_err
] method.
Example
// A service returning Result<_, Error>
let service = DatabaseService::new("127.0.0.1:8080");
// Map the error to a new error
let mut new_service = service.map_err(|err| err.code);
// Call the new service
let id = 13;
let code = new_service
.ready()
.await?
.call(id)
.await
.unwrap_err();
sourcefn map_result<F, Response, Error>(self, f: F) -> MapResult<Self, F>where
Self: Sized,
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Result<Response, Error> + Clone,
fn map_result<F, Response, Error>(self, f: F) -> MapResult<Self, F>where
Self: Sized,
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Result<Response, Error> + Clone,
Maps this service’s result type (Result<Self::Response, Self::Error>
)
to a different value, regardless of whether the future succeeds or
fails.
This is similar to the map_response
and map_err
combinators,
except that the same function is invoked when the service’s future
completes, whether it completes successfully or fails. This function
takes the [Result
] returned by the service’s future, and returns a
[Result
].
Like the standard library’s [Result::and_then
], this method can be
used to implement control flow based on Result
values. For example, it
may be used to implement error recovery, by turning some [Err
]
responses from the service into [Ok
] responses. Similarly, some
successful responses from the service could be rejected, by returning an
[Err
] conditionally, depending on the value inside the [Ok
.] Finally,
this method can also be used to implement behaviors that must run when a
service’s future completes, regardless of whether it succeeded or failed.
This method can be used to change the Response
type of the service
into a different type. It can also be used to change the Error
type
of the service. However, because the map_result
function is not applied
to the errors returned by the service’s poll_ready
method, it must
be possible to convert the service’s Error
type into the error type
returned by the map_result
function. This is trivial when the function
returns the same error type as the service, but in other cases, it can
be useful to use BoxError
to erase differing error types.
Examples
Recovering from certain errors:
// A service returning Result<Vec<Record>, DbError>
let service = DatabaseService::new("127.0.0.1:8080");
// If the database returns no records for the query, we just want an empty `Vec`.
let mut new_service = service.map_result(|result| match result {
// If the error indicates that no records matched the query, return an empty
// `Vec` instead.
Err(DbError::NoRecordsFound) => Ok(Vec::new()),
// Propagate all other responses (`Ok` and `Err`) unchanged
x => x,
});
// Call the new service
let id = 13;
let name = new_service
.ready()
.await?
.call(id)
.await?;
Rejecting some Ok
responses:
use tower::BoxError;
// A service returning Result<Record, DbError>
let service = DatabaseService::new("127.0.0.1:8080");
// If the user is zero years old, return an error.
let mut new_service = service.map_result(|result| {
let record = result?;
if record.age == 0 {
// Users must have been born to use our app!
let app_error = AppError::from("users cannot be 0 years old!");
// Box the error to erase its type (as it can be an `AppError`
// *or* the inner service's `DbError`).
return Err(BoxError::from(app_error));
}
// Otherwise, return the record.
Ok(record)
});
// Call the new service
let id = 13;
let record = new_service
.ready()
.await?
.call(id)
.await?;
Performing an action that must be run for both successes and failures:
// A service returning Result<Record, DbError>
let service = DatabaseService::new("127.0.0.1:8080");
// Print a message whenever a query completes.
let mut new_service = service.map_result(|result| {
println!("query completed; success={}", result.is_ok());
result
});
// Call the new service
let id = 13;
let response = new_service
.ready()
.await?
.call(id)
.await;
sourcefn map_request<F, NewRequest>(self, f: F) -> MapRequest<Self, F>where
Self: Sized,
F: FnMut(NewRequest) -> Request,
fn map_request<F, NewRequest>(self, f: F) -> MapRequest<Self, F>where
Self: Sized,
F: FnMut(NewRequest) -> Request,
Composes a function in front of the service.
This adapter produces a new service that passes each value through the
given function f
before sending it to self
.
Example
// A service taking a String as a request
let service = DatabaseService::new("127.0.0.1:8080");
// Map the request to a new request
let mut new_service = service.map_request(|id: u32| id.to_string());
// Call the new service
let id = 13;
let response = new_service
.ready()
.await?
.call(id)
.await;
sourcefn then<F, Response, Error, Fut>(self, f: F) -> Then<Self, F>where
Self: Sized,
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Fut + Clone,
Fut: Future<Output = Result<Response, Error>>,
fn then<F, Response, Error, Fut>(self, f: F) -> Then<Self, F>where
Self: Sized,
Error: From<Self::Error>,
F: FnOnce(Result<Self::Response, Self::Error>) -> Fut + Clone,
Fut: Future<Output = Result<Response, Error>>,
Composes an asynchronous function after this service.
This takes a function or closure returning a future, and returns a new
Service
that chains that function after this service’s Future
. The
new Service
’s future will consist of this service’s future, followed
by the future returned by calling the chained function with the future’s
Output
type. The chained function is called regardless of whether
this service’s future completes with a successful response or with an
error.
This method can be thought of as an equivalent to the futures
crate’s FutureExt::then
combinator, but acting on Service
s that
return futures, rather than on an individual future. Similarly to that
combinator, ServiceExt::then
can be used to implement asynchronous
error recovery, by calling some asynchronous function with errors
returned by this service. Alternatively, it may also be used to call a
fallible async function with the successful response of this service.
This method can be used to change the Response
type of the service
into a different type. It can also be used to change the Error
type
of the service. However, because the then
function is not applied
to the errors returned by the service’s poll_ready
method, it must
be possible to convert the service’s Error
type into the error type
returned by the then
future. This is trivial when the function
returns the same error type as the service, but in other cases, it can
be useful to use BoxError
to erase differing error types.
Examples
// A service returning Result<Record, DbError>
let service = DatabaseService::new("127.0.0.1:8080");
// An async function that attempts to recover from errors returned by the
// database.
async fn recover_from_error(error: DbError) -> Result<Record, DbError> {
// ...
}
// If the database service returns an error, attempt to recover by
// calling `recover_from_error`. Otherwise, return the successful response.
let mut new_service = service.then(|result| async move {
match result {
Ok(record) => Ok(record),
Err(e) => recover_from_error(e).await,
}
});
// Call the new service
let id = 13;
let record = new_service
.ready()
.await?
.call(id)
.await?;
sourcefn map_future<F, Fut, Response, Error>(self, f: F) -> MapFuture<Self, F>where
Self: Sized,
F: FnMut(Self::Future) -> Fut,
Error: From<Self::Error>,
Fut: Future<Output = Result<Response, Error>>,
fn map_future<F, Fut, Response, Error>(self, f: F) -> MapFuture<Self, F>where
Self: Sized,
F: FnMut(Self::Future) -> Fut,
Error: From<Self::Error>,
Fut: Future<Output = Result<Response, Error>>,
Composes a function that transforms futures produced by the service.
This takes a function or closure returning a future computed from the future returned by
the service’s call
method, as opposed to the responses produced by the future.
Examples
use std::time::Duration;
use tokio::time::timeout;
// A service returning Result<Record, DbError>
let service = DatabaseService::new("127.0.0.1:8080");
let mut new_service = service.map_future(|future| async move {
let res = timeout(Duration::from_secs(1), future).await?;
Ok::<_, BoxError>(res)
});
// Call the new service
let id = 13;
let record = new_service
.ready()
.await?
.call(id)
.await?;
Note that normally you wouldn’t implement timeouts like this and instead use Timeout
.
sourcefn boxed(self) -> BoxService<Request, Self::Response, Self::Error>where
Self: Sized + Send + 'static,
Self::Future: Send + 'static,
fn boxed(self) -> BoxService<Request, Self::Response, Self::Error>where
Self: Sized + Send + 'static,
Self::Future: Send + 'static,
Convert the service into a Service
+ [Send
] trait object.
See BoxService
for more details.
If Self
implements the [Clone
] trait, the boxed_clone
method
can be used instead, to produce a boxed service which will also
implement [Clone
].
Example
use tower::{Service, ServiceExt, BoxError, service_fn, util::BoxService};
let service = service_fn(|req: Request| async {
Ok::<_, BoxError>(Response::new())
});
let service: BoxService<Request, Response, BoxError> = service
.map_request(|req| {
println!("received request");
req
})
.map_response(|res| {
println!("response produced");
res
})
.boxed();
sourcefn boxed_clone(self) -> BoxCloneService<Request, Self::Response, Self::Error>where
Self: Clone + Sized + Send + 'static,
Self::Future: Send + 'static,
fn boxed_clone(self) -> BoxCloneService<Request, Self::Response, Self::Error>where
Self: Clone + Sized + Send + 'static,
Self::Future: Send + 'static,
Convert the service into a Service
+ [Clone
] + [Send
] trait object.
This is similar to the boxed
method, but it requires that Self
implement
[Clone
], and the returned boxed service implements [Clone
].
See BoxCloneService
for more details.
Example
use tower::{Service, ServiceExt, BoxError, service_fn, util::BoxCloneService};
let service = service_fn(|req: Request| async {
Ok::<_, BoxError>(Response::new())
});
let service: BoxCloneService<Request, Response, BoxError> = service
.map_request(|req| {
println!("received request");
req
})
.map_response(|res| {
println!("response produced");
res
})
.boxed_clone();
// The boxed service can still be cloned.
service.clone();