| //! Builder types to compose layers and services |
| |
| use tower_layer::{Identity, Layer, Stack}; |
| use tower_service::Service; |
| |
| use std::fmt; |
| |
| /// Declaratively construct [`Service`] values. |
| /// |
| /// [`ServiceBuilder`] provides a [builder-like interface][builder] for composing |
| /// layers to be applied to a [`Service`]. |
| /// |
| /// # Service |
| /// |
| /// A [`Service`] is a trait representing an asynchronous function of a request |
| /// to a response. It is similar to `async fn(Request) -> Result<Response, Error>`. |
| /// |
| /// A [`Service`] is typically bound to a single transport, such as a TCP |
| /// connection. It defines how _all_ inbound or outbound requests are handled |
| /// by that connection. |
| /// |
| /// [builder]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html |
| /// |
| /// # Order |
| /// |
| /// The order in which layers are added impacts how requests are handled. Layers |
| /// that are added first will be called with the request first. The argument to |
| /// `service` will be last to see the request. |
| /// |
| /// ``` |
| /// # // this (and other) doctest is ignored because we don't have a way |
| /// # // to say that it should only be run with cfg(feature = "...") |
| /// # use tower::Service; |
| /// # use tower::builder::ServiceBuilder; |
| /// # #[cfg(all(feature = "buffer", feature = "limit"))] |
| /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
| /// ServiceBuilder::new() |
| /// .buffer(100) |
| /// .concurrency_limit(10) |
| /// .service(svc) |
| /// # ; |
| /// # } |
| /// ``` |
| /// |
| /// In the above example, the buffer layer receives the request first followed |
| /// by `concurrency_limit`. `buffer` enables up to 100 request to be in-flight |
| /// **on top of** the requests that have already been forwarded to the next |
| /// layer. Combined with `concurrency_limit`, this allows up to 110 requests to be |
| /// in-flight. |
| /// |
| /// ``` |
| /// # use tower::Service; |
| /// # use tower::builder::ServiceBuilder; |
| /// # #[cfg(all(feature = "buffer", feature = "limit"))] |
| /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
| /// ServiceBuilder::new() |
| /// .concurrency_limit(10) |
| /// .buffer(100) |
| /// .service(svc) |
| /// # ; |
| /// # } |
| /// ``` |
| /// |
| /// The above example is similar, but the order of layers is reversed. Now, |
| /// `concurrency_limit` applies first and only allows 10 requests to be in-flight |
| /// total. |
| /// |
| /// # Examples |
| /// |
| /// A [`Service`] stack with a single layer: |
| /// |
| /// ``` |
| /// # use tower::Service; |
| /// # use tower::builder::ServiceBuilder; |
| /// # #[cfg(feature = "limit")] |
| /// # use tower::limit::concurrency::ConcurrencyLimitLayer; |
| /// # #[cfg(feature = "limit")] |
| /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
| /// ServiceBuilder::new() |
| /// .concurrency_limit(5) |
| /// .service(svc); |
| /// # ; |
| /// # } |
| /// ``` |
| /// |
| /// A [`Service`] stack with _multiple_ layers that contain rate limiting, |
| /// in-flight request limits, and a channel-backed, clonable [`Service`]: |
| /// |
| /// ``` |
| /// # use tower::Service; |
| /// # use tower::builder::ServiceBuilder; |
| /// # use std::time::Duration; |
| /// # #[cfg(all(feature = "buffer", feature = "limit"))] |
| /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
| /// ServiceBuilder::new() |
| /// .buffer(5) |
| /// .concurrency_limit(5) |
| /// .rate_limit(5, Duration::from_secs(1)) |
| /// .service(svc); |
| /// # ; |
| /// # } |
| /// ``` |
| /// |
| /// [`Service`]: crate::Service |
| #[derive(Clone)] |
| pub struct ServiceBuilder<L> { |
| layer: L, |
| } |
| |
| impl Default for ServiceBuilder<Identity> { |
| fn default() -> Self { |
| Self::new() |
| } |
| } |
| |
| impl ServiceBuilder<Identity> { |
| /// Create a new [`ServiceBuilder`]. |
| pub fn new() -> Self { |
| ServiceBuilder { |
| layer: Identity::new(), |
| } |
| } |
| } |
| |
| impl<L> ServiceBuilder<L> { |
| /// Add a new layer `T` into the [`ServiceBuilder`]. |
| /// |
| /// This wraps the inner service with the service provided by a user-defined |
| /// [`Layer`]. The provided layer must implement the [`Layer`] trait. |
| /// |
| /// [`Layer`]: crate::Layer |
| pub fn layer<T>(self, layer: T) -> ServiceBuilder<Stack<T, L>> { |
| ServiceBuilder { |
| layer: Stack::new(layer, self.layer), |
| } |
| } |
| |
| /// Optionally add a new layer `T` into the [`ServiceBuilder`]. |
| /// |
| /// ``` |
| /// # use std::time::Duration; |
| /// # use tower::Service; |
| /// # use tower::builder::ServiceBuilder; |
| /// # use tower::timeout::TimeoutLayer; |
| /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
| /// # let timeout = Some(Duration::new(10, 0)); |
| /// // Apply a timeout if configured |
| /// ServiceBuilder::new() |
| /// .option_layer(timeout.map(TimeoutLayer::new)) |
| /// .service(svc) |
| /// # ; |
| /// # } |
| /// ``` |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn option_layer<T>( |
| self, |
| layer: Option<T>, |
| ) -> ServiceBuilder<Stack<crate::util::Either<T, Identity>, L>> { |
| self.layer(crate::util::option_layer(layer)) |
| } |
| |
| /// Add a [`Layer`] built from a function that accepts a service and returns another service. |
| /// |
| /// See the documentation for [`layer_fn`] for more details. |
| /// |
| /// [`layer_fn`]: crate::layer::layer_fn |
| pub fn layer_fn<F>(self, f: F) -> ServiceBuilder<Stack<crate::layer::LayerFn<F>, L>> { |
| self.layer(crate::layer::layer_fn(f)) |
| } |
| |
| /// Buffer requests when the next layer is not ready. |
| /// |
| /// This wraps the inner service with an instance of the [`Buffer`] |
| /// middleware. |
| /// |
| /// [`Buffer`]: crate::buffer |
| #[cfg(feature = "buffer")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "buffer")))] |
| pub fn buffer<Request>( |
| self, |
| bound: usize, |
| ) -> ServiceBuilder<Stack<crate::buffer::BufferLayer<Request>, L>> { |
| self.layer(crate::buffer::BufferLayer::new(bound)) |
| } |
| |
| /// Limit the max number of in-flight requests. |
| /// |
| /// A request is in-flight from the time the request is received until the |
| /// response future completes. This includes the time spent in the next |
| /// layers. |
| /// |
| /// This wraps the inner service with an instance of the |
| /// [`ConcurrencyLimit`] middleware. |
| /// |
| /// [`ConcurrencyLimit`]: crate::limit::concurrency |
| #[cfg(feature = "limit")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "limit")))] |
| pub fn concurrency_limit( |
| self, |
| max: usize, |
| ) -> ServiceBuilder<Stack<crate::limit::ConcurrencyLimitLayer, L>> { |
| self.layer(crate::limit::ConcurrencyLimitLayer::new(max)) |
| } |
| |
| /// Drop requests when the next layer is unable to respond to requests. |
| /// |
| /// Usually, when a service or middleware does not have capacity to process a |
| /// request (i.e., [`poll_ready`] returns [`Pending`]), the caller waits until |
| /// capacity becomes available. |
| /// |
| /// [`LoadShed`] immediately responds with an error when the next layer is |
| /// out of capacity. |
| /// |
| /// This wraps the inner service with an instance of the [`LoadShed`] |
| /// middleware. |
| /// |
| /// [`LoadShed`]: crate::load_shed |
| /// [`poll_ready`]: crate::Service::poll_ready |
| /// [`Pending`]: std::task::Poll::Pending |
| #[cfg(feature = "load-shed")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "load-shed")))] |
| pub fn load_shed(self) -> ServiceBuilder<Stack<crate::load_shed::LoadShedLayer, L>> { |
| self.layer(crate::load_shed::LoadShedLayer::new()) |
| } |
| |
| /// Limit requests to at most `num` per the given duration. |
| /// |
| /// This wraps the inner service with an instance of the [`RateLimit`] |
| /// middleware. |
| /// |
| /// [`RateLimit`]: crate::limit::rate |
| #[cfg(feature = "limit")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "limit")))] |
| pub fn rate_limit( |
| self, |
| num: u64, |
| per: std::time::Duration, |
| ) -> ServiceBuilder<Stack<crate::limit::RateLimitLayer, L>> { |
| self.layer(crate::limit::RateLimitLayer::new(num, per)) |
| } |
| |
| /// Retry failed requests according to the given [retry policy][policy]. |
| /// |
| /// `policy` determines which failed requests will be retried. It must |
| /// implement the [`retry::Policy`][policy] trait. |
| /// |
| /// This wraps the inner service with an instance of the [`Retry`] |
| /// middleware. |
| /// |
| /// [`Retry`]: crate::retry |
| /// [policy]: crate::retry::Policy |
| #[cfg(feature = "retry")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "retry")))] |
| pub fn retry<P>(self, policy: P) -> ServiceBuilder<Stack<crate::retry::RetryLayer<P>, L>> { |
| self.layer(crate::retry::RetryLayer::new(policy)) |
| } |
| |
| /// Fail requests that take longer than `timeout`. |
| /// |
| /// If the next layer takes more than `timeout` to respond to a request, |
| /// processing is terminated and an error is returned. |
| /// |
| /// This wraps the inner service with an instance of the [`timeout`] |
| /// middleware. |
| /// |
| /// [`timeout`]: crate::timeout |
| #[cfg(feature = "timeout")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "timeout")))] |
| pub fn timeout( |
| self, |
| timeout: std::time::Duration, |
| ) -> ServiceBuilder<Stack<crate::timeout::TimeoutLayer, L>> { |
| self.layer(crate::timeout::TimeoutLayer::new(timeout)) |
| } |
| |
| /// Conditionally reject requests based on `predicate`. |
| /// |
| /// `predicate` must implement the [`Predicate`] trait. |
| /// |
| /// This wraps the inner service with an instance of the [`Filter`] |
| /// middleware. |
| /// |
| /// [`Filter`]: crate::filter |
| /// [`Predicate`]: crate::filter::Predicate |
| #[cfg(feature = "filter")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "filter")))] |
| pub fn filter<P>( |
| self, |
| predicate: P, |
| ) -> ServiceBuilder<Stack<crate::filter::FilterLayer<P>, L>> { |
| self.layer(crate::filter::FilterLayer::new(predicate)) |
| } |
| |
| /// Conditionally reject requests based on an asynchronous `predicate`. |
| /// |
| /// `predicate` must implement the [`AsyncPredicate`] trait. |
| /// |
| /// This wraps the inner service with an instance of the [`AsyncFilter`] |
| /// middleware. |
| /// |
| /// [`AsyncFilter`]: crate::filter::AsyncFilter |
| /// [`AsyncPredicate`]: crate::filter::AsyncPredicate |
| #[cfg(feature = "filter")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "filter")))] |
| pub fn filter_async<P>( |
| self, |
| predicate: P, |
| ) -> ServiceBuilder<Stack<crate::filter::AsyncFilterLayer<P>, L>> { |
| self.layer(crate::filter::AsyncFilterLayer::new(predicate)) |
| } |
| |
| /// Map one request type to another. |
| /// |
| /// This wraps the inner service with an instance of the [`MapRequest`] |
| /// middleware. |
| /// |
| /// # Examples |
| /// |
| /// Changing the type of a request: |
| /// |
| /// ```rust |
| /// use tower::ServiceBuilder; |
| /// use tower::ServiceExt; |
| /// |
| /// # #[tokio::main] |
| /// # async fn main() -> Result<(), ()> { |
| /// // Suppose we have some `Service` whose request type is `String`: |
| /// let string_svc = tower::service_fn(|request: String| async move { |
| /// println!("request: {}", request); |
| /// Ok(()) |
| /// }); |
| /// |
| /// // ...but we want to call that service with a `usize`. What do we do? |
| /// |
| /// let usize_svc = ServiceBuilder::new() |
| /// // Add a middlware that converts the request type to a `String`: |
| /// .map_request(|request: usize| format!("{}", request)) |
| /// // ...and wrap the string service with that middleware: |
| /// .service(string_svc); |
| /// |
| /// // Now, we can call that service with a `usize`: |
| /// usize_svc.oneshot(42).await?; |
| /// # Ok(()) |
| /// # } |
| /// ``` |
| /// |
| /// Modifying the request value: |
| /// |
| /// ```rust |
| /// use tower::ServiceBuilder; |
| /// use tower::ServiceExt; |
| /// |
| /// # #[tokio::main] |
| /// # async fn main() -> Result<(), ()> { |
| /// // A service that takes a number and returns it: |
| /// let svc = tower::service_fn(|request: usize| async move { |
| /// Ok(request) |
| /// }); |
| /// |
| /// let svc = ServiceBuilder::new() |
| /// // Add a middleware that adds 1 to each request |
| /// .map_request(|request: usize| request + 1) |
| /// .service(svc); |
| /// |
| /// let response = svc.oneshot(1).await?; |
| /// assert_eq!(response, 2); |
| /// # Ok(()) |
| /// # } |
| /// ``` |
| /// |
| /// [`MapRequest`]: crate::util::MapRequest |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn map_request<F, R1, R2>( |
| self, |
| f: F, |
| ) -> ServiceBuilder<Stack<crate::util::MapRequestLayer<F>, L>> |
| where |
| F: FnMut(R1) -> R2 + Clone, |
| { |
| self.layer(crate::util::MapRequestLayer::new(f)) |
| } |
| |
| /// Map one response type to another. |
| /// |
| /// This wraps the inner service with an instance of the [`MapResponse`] |
| /// middleware. |
| /// |
| /// See the documentation for the [`map_response` combinator] for details. |
| /// |
| /// [`MapResponse`]: crate::util::MapResponse |
| /// [`map_response` combinator]: crate::util::ServiceExt::map_response |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn map_response<F>( |
| self, |
| f: F, |
| ) -> ServiceBuilder<Stack<crate::util::MapResponseLayer<F>, L>> { |
| self.layer(crate::util::MapResponseLayer::new(f)) |
| } |
| |
| /// Map one error type to another. |
| /// |
| /// This wraps the inner service with an instance of the [`MapErr`] |
| /// middleware. |
| /// |
| /// See the documentation for the [`map_err` combinator] for details. |
| /// |
| /// [`MapErr`]: crate::util::MapErr |
| /// [`map_err` combinator]: crate::util::ServiceExt::map_err |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn map_err<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::MapErrLayer<F>, L>> { |
| self.layer(crate::util::MapErrLayer::new(f)) |
| } |
| |
| /// Composes a function that transforms futures produced by the service. |
| /// |
| /// This wraps the inner service with an instance of the [`MapFutureLayer`] middleware. |
| /// |
| /// See the documentation for the [`map_future`] combinator for details. |
| /// |
| /// [`MapFutureLayer`]: crate::util::MapFutureLayer |
| /// [`map_future`]: crate::util::ServiceExt::map_future |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn map_future<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::MapFutureLayer<F>, L>> { |
| self.layer(crate::util::MapFutureLayer::new(f)) |
| } |
| |
| /// Apply an asynchronous function after the service, regardless of whether the future |
| /// succeeds or fails. |
| /// |
| /// This wraps the inner service with an instance of the [`Then`] |
| /// middleware. |
| /// |
| /// This is similar to the [`map_response`] and [`map_err`] functions, |
| /// 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`]. |
| /// |
| /// See the documentation for the [`then` combinator] for details. |
| /// |
| /// [`Then`]: crate::util::Then |
| /// [`then` combinator]: crate::util::ServiceExt::then |
| /// [`map_response`]: ServiceBuilder::map_response |
| /// [`map_err`]: ServiceBuilder::map_err |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn then<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::ThenLayer<F>, L>> { |
| self.layer(crate::util::ThenLayer::new(f)) |
| } |
| |
| /// 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. |
| /// |
| /// This wraps the inner service with an instance of the [`AndThen`] |
| /// middleware. |
| /// |
| /// See the documentation for the [`and_then` combinator] for details. |
| /// |
| /// [`Response`]: crate::Service::Response |
| /// [`poll_ready`]: crate::Service::poll_ready |
| /// [`and_then` combinator]: crate::util::ServiceExt::and_then |
| /// [`AndThen`]: crate::util::AndThen |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn and_then<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::AndThenLayer<F>, L>> { |
| self.layer(crate::util::AndThenLayer::new(f)) |
| } |
| |
| /// Maps this service's result type (`Result<Self::Response, Self::Error>`) |
| /// to a different value, regardless of whether the future succeeds or |
| /// fails. |
| /// |
| /// This wraps the inner service with an instance of the [`MapResult`] |
| /// middleware. |
| /// |
| /// See the documentation for the [`map_result` combinator] for details. |
| /// |
| /// [`map_result` combinator]: crate::util::ServiceExt::map_result |
| /// [`MapResult`]: crate::util::MapResult |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn map_result<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::MapResultLayer<F>, L>> { |
| self.layer(crate::util::MapResultLayer::new(f)) |
| } |
| |
| /// Returns the underlying `Layer` implementation. |
| pub fn into_inner(self) -> L { |
| self.layer |
| } |
| |
| /// Wrap the service `S` with the middleware provided by this |
| /// [`ServiceBuilder`]'s [`Layer`]'s, returning a new [`Service`]. |
| /// |
| /// [`Layer`]: crate::Layer |
| /// [`Service`]: crate::Service |
| pub fn service<S>(&self, service: S) -> L::Service |
| where |
| L: Layer<S>, |
| { |
| self.layer.layer(service) |
| } |
| |
| /// Wrap the async function `F` with the middleware provided by this [`ServiceBuilder`]'s |
| /// [`Layer`]s, returning a new [`Service`]. |
| /// |
| /// This is a convenience method which is equivalent to calling |
| /// [`ServiceBuilder::service`] with a [`service_fn`], like this: |
| /// |
| /// ```rust |
| /// # use tower::{ServiceBuilder, service_fn}; |
| /// # async fn handler_fn(_: ()) -> Result<(), ()> { Ok(()) } |
| /// # let _ = { |
| /// ServiceBuilder::new() |
| /// // ... |
| /// .service(service_fn(handler_fn)) |
| /// # }; |
| /// ``` |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// use std::time::Duration; |
| /// use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; |
| /// |
| /// # #[tokio::main] |
| /// # async fn main() -> Result<(), BoxError> { |
| /// async fn handle(request: &'static str) -> Result<&'static str, BoxError> { |
| /// Ok(request) |
| /// } |
| /// |
| /// let svc = ServiceBuilder::new() |
| /// .buffer(1024) |
| /// .timeout(Duration::from_secs(10)) |
| /// .service_fn(handle); |
| /// |
| /// let response = svc.oneshot("foo").await?; |
| /// |
| /// assert_eq!(response, "foo"); |
| /// # Ok(()) |
| /// # } |
| /// ``` |
| /// |
| /// [`Layer`]: crate::Layer |
| /// [`Service`]: crate::Service |
| /// [`service_fn`]: crate::service_fn |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn service_fn<F>(self, f: F) -> L::Service |
| where |
| L: Layer<crate::util::ServiceFn<F>>, |
| { |
| self.service(crate::util::service_fn(f)) |
| } |
| |
| /// Check that the builder implements `Clone`. |
| /// |
| /// This can be useful when debugging type errors in `ServiceBuilder`s with lots of layers. |
| /// |
| /// Doesn't actually change the builder but serves as a type check. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// use tower::ServiceBuilder; |
| /// |
| /// let builder = ServiceBuilder::new() |
| /// // Do something before processing the request |
| /// .map_request(|request: String| { |
| /// println!("got request!"); |
| /// request |
| /// }) |
| /// // Ensure our `ServiceBuilder` can be cloned |
| /// .check_clone() |
| /// // Do something after processing the request |
| /// .map_response(|response: String| { |
| /// println!("got response!"); |
| /// response |
| /// }); |
| /// ``` |
| #[inline] |
| pub fn check_clone(self) -> Self |
| where |
| Self: Clone, |
| { |
| self |
| } |
| |
| /// Check that the builder when given a service of type `S` produces a service that implements |
| /// `Clone`. |
| /// |
| /// This can be useful when debugging type errors in `ServiceBuilder`s with lots of layers. |
| /// |
| /// Doesn't actually change the builder but serves as a type check. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// use tower::ServiceBuilder; |
| /// |
| /// # #[derive(Clone)] |
| /// # struct MyService; |
| /// # |
| /// let builder = ServiceBuilder::new() |
| /// // Do something before processing the request |
| /// .map_request(|request: String| { |
| /// println!("got request!"); |
| /// request |
| /// }) |
| /// // Ensure that the service produced when given a `MyService` implements |
| /// .check_service_clone::<MyService>() |
| /// // Do something after processing the request |
| /// .map_response(|response: String| { |
| /// println!("got response!"); |
| /// response |
| /// }); |
| /// ``` |
| #[inline] |
| pub fn check_service_clone<S>(self) -> Self |
| where |
| L: Layer<S>, |
| L::Service: Clone, |
| { |
| self |
| } |
| |
| /// Check that the builder when given a service of type `S` produces a service with the given |
| /// request, response, and error types. |
| /// |
| /// This can be useful when debugging type errors in `ServiceBuilder`s with lots of layers. |
| /// |
| /// Doesn't actually change the builder but serves as a type check. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// use tower::ServiceBuilder; |
| /// use std::task::{Poll, Context}; |
| /// use tower::{Service, ServiceExt}; |
| /// |
| /// // An example service |
| /// struct MyService; |
| /// |
| /// impl Service<Request> for MyService { |
| /// type Response = Response; |
| /// type Error = Error; |
| /// type Future = futures_util::future::Ready<Result<Response, Error>>; |
| /// |
| /// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { |
| /// // ... |
| /// # todo!() |
| /// } |
| /// |
| /// fn call(&mut self, request: Request) -> Self::Future { |
| /// // ... |
| /// # todo!() |
| /// } |
| /// } |
| /// |
| /// struct Request; |
| /// struct Response; |
| /// struct Error; |
| /// |
| /// struct WrappedResponse(Response); |
| /// |
| /// let builder = ServiceBuilder::new() |
| /// // At this point in the builder if given a `MyService` it produces a service that |
| /// // accepts `Request`s, produces `Response`s, and fails with `Error`s |
| /// .check_service::<MyService, Request, Response, Error>() |
| /// // Wrap responses in `WrappedResponse` |
| /// .map_response(|response: Response| WrappedResponse(response)) |
| /// // Now the response type will be `WrappedResponse` |
| /// .check_service::<MyService, _, WrappedResponse, _>(); |
| /// ``` |
| #[inline] |
| pub fn check_service<S, T, U, E>(self) -> Self |
| where |
| L: Layer<S>, |
| L::Service: Service<T, Response = U, Error = E>, |
| { |
| self |
| } |
| |
| /// This wraps the inner service with the [`Layer`] returned by [`BoxService::layer()`]. |
| /// |
| /// See that method for more details. |
| /// |
| /// # Example |
| /// |
| /// ``` |
| /// use tower::{Service, ServiceBuilder, BoxError, util::BoxService}; |
| /// use std::time::Duration; |
| /// # |
| /// # struct Request; |
| /// # struct Response; |
| /// # impl Response { |
| /// # fn new() -> Self { Self } |
| /// # } |
| /// |
| /// let service: BoxService<Request, Response, BoxError> = ServiceBuilder::new() |
| /// .boxed() |
| /// .load_shed() |
| /// .concurrency_limit(64) |
| /// .timeout(Duration::from_secs(10)) |
| /// .service_fn(|req: Request| async { |
| /// Ok::<_, BoxError>(Response::new()) |
| /// }); |
| /// # let service = assert_service(service); |
| /// # fn assert_service<S, R>(svc: S) -> S |
| /// # where S: Service<R> { svc } |
| /// ``` |
| /// |
| /// [`BoxService::layer()`]: crate::util::BoxService::layer() |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn boxed<S, R>( |
| self, |
| ) -> ServiceBuilder< |
| Stack< |
| tower_layer::LayerFn< |
| fn( |
| L::Service, |
| ) -> crate::util::BoxService< |
| R, |
| <L::Service as Service<R>>::Response, |
| <L::Service as Service<R>>::Error, |
| >, |
| >, |
| L, |
| >, |
| > |
| where |
| L: Layer<S>, |
| L::Service: Service<R> + Send + 'static, |
| <L::Service as Service<R>>::Future: Send + 'static, |
| { |
| self.layer(crate::util::BoxService::layer()) |
| } |
| |
| /// This wraps the inner service with the [`Layer`] returned by [`BoxCloneService::layer()`]. |
| /// |
| /// 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, ServiceBuilder, BoxError, util::BoxCloneService}; |
| /// use std::time::Duration; |
| /// # |
| /// # struct Request; |
| /// # struct Response; |
| /// # impl Response { |
| /// # fn new() -> Self { Self } |
| /// # } |
| /// |
| /// let service: BoxCloneService<Request, Response, BoxError> = ServiceBuilder::new() |
| /// .boxed_clone() |
| /// .load_shed() |
| /// .concurrency_limit(64) |
| /// .timeout(Duration::from_secs(10)) |
| /// .service_fn(|req: Request| async { |
| /// Ok::<_, BoxError>(Response::new()) |
| /// }); |
| /// # let service = assert_service(service); |
| /// |
| /// // The boxed service can still be cloned. |
| /// service.clone(); |
| /// # fn assert_service<S, R>(svc: S) -> S |
| /// # where S: Service<R> { svc } |
| /// ``` |
| /// |
| /// [`BoxCloneService::layer()`]: crate::util::BoxCloneService::layer() |
| /// [`BoxCloneService`]: crate::util::BoxCloneService |
| /// [`boxed`]: Self::boxed |
| #[cfg(feature = "util")] |
| #[cfg_attr(docsrs, doc(cfg(feature = "util")))] |
| pub fn boxed_clone<S, R>( |
| self, |
| ) -> ServiceBuilder< |
| Stack< |
| tower_layer::LayerFn< |
| fn( |
| L::Service, |
| ) -> crate::util::BoxCloneService< |
| R, |
| <L::Service as Service<R>>::Response, |
| <L::Service as Service<R>>::Error, |
| >, |
| >, |
| L, |
| >, |
| > |
| where |
| L: Layer<S>, |
| L::Service: Service<R> + Clone + Send + 'static, |
| <L::Service as Service<R>>::Future: Send + 'static, |
| { |
| self.layer(crate::util::BoxCloneService::layer()) |
| } |
| } |
| |
| impl<L: fmt::Debug> fmt::Debug for ServiceBuilder<L> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| f.debug_tuple("ServiceBuilder").field(&self.layer).finish() |
| } |
| } |
| |
| impl<S, L> Layer<S> for ServiceBuilder<L> |
| where |
| L: Layer<S>, |
| { |
| type Service = L::Service; |
| |
| fn layer(&self, inner: S) -> Self::Service { |
| self.layer.layer(inner) |
| } |
| } |