tower_async_http/set_status.rs
1//! Middleware to override status codes.
2//!
3//! # Example
4//!
5//! ```
6//! use tower_async_http::set_status::SetStatusLayer;
7//! use http::{Request, Response, StatusCode};
8//! use http_body_util::Full;
9//! use bytes::Bytes;
10//! use std::{iter::once, convert::Infallible};
11//! use tower_async::{ServiceBuilder, Service, ServiceExt};
12//!
13//! async fn handle(req: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, Infallible> {
14//! // ...
15//! # Ok(Response::new(Full::default()))
16//! }
17//!
18//! # #[tokio::main]
19//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
20//! let mut service = ServiceBuilder::new()
21//! // change the status to `404 Not Found` regardless what the inner service returns
22//! .layer(SetStatusLayer::new(StatusCode::NOT_FOUND))
23//! .service_fn(handle);
24//!
25//! // Call the service.
26//! let request = Request::builder().body(Full::default())?;
27//!
28//! let response = service.call(request).await?;
29//!
30//! assert_eq!(response.status(), StatusCode::NOT_FOUND);
31//! #
32//! # Ok(())
33//! # }
34//! ```
35
36use http::{Request, Response, StatusCode};
37
38use tower_async_layer::Layer;
39use tower_async_service::Service;
40
41/// Layer that applies [`SetStatus`] which overrides the status codes.
42#[derive(Debug, Clone, Copy)]
43pub struct SetStatusLayer {
44 status: StatusCode,
45}
46
47impl SetStatusLayer {
48 /// Create a new [`SetStatusLayer`].
49 ///
50 /// The response status code will be `status` regardless of what the inner service returns.
51 pub fn new(status: StatusCode) -> Self {
52 SetStatusLayer { status }
53 }
54}
55
56impl<S> Layer<S> for SetStatusLayer {
57 type Service = SetStatus<S>;
58
59 fn layer(&self, inner: S) -> Self::Service {
60 SetStatus::new(inner, self.status)
61 }
62}
63
64/// Middleware to override status codes.
65///
66/// See the [module docs](self) for more details.
67#[derive(Debug, Clone, Copy)]
68pub struct SetStatus<S> {
69 inner: S,
70 status: StatusCode,
71}
72
73impl<S> SetStatus<S> {
74 /// Create a new [`SetStatus`].
75 ///
76 /// The response status code will be `status` regardless of what the inner service returns.
77 pub fn new(inner: S, status: StatusCode) -> Self {
78 Self { status, inner }
79 }
80
81 define_inner_service_accessors!();
82
83 /// Returns a new [`Layer`] that wraps services with a `SetStatus` middleware.
84 ///
85 /// [`Layer`]: tower_async_layer::Layer
86 pub fn layer(status: StatusCode) -> SetStatusLayer {
87 SetStatusLayer::new(status)
88 }
89}
90
91impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for SetStatus<S>
92where
93 S: Service<Request<ReqBody>, Response = Response<ResBody>>,
94{
95 type Response = S::Response;
96 type Error = S::Error;
97
98 async fn call(&self, req: Request<ReqBody>) -> Result<Self::Response, Self::Error> {
99 let mut response = self.inner.call(req).await?;
100 *response.status_mut() = self.status;
101 Ok(response)
102 }
103}