mirror of
https://github.com/tokio-rs/axum.git
synced 2025-03-21 22:48:51 +01:00
Support turning any Service
into a MakeService
(#1302)
* Add `ServiceExt` * changelog
This commit is contained in:
parent
ab36e65449
commit
fa51cf5266
6 changed files with 98 additions and 1 deletions
axum
|
@ -363,6 +363,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- **fixed:** Annotate panicking functions with `#[track_caller]` so the error
|
||||
message points to where the user added the invalid route, rather than
|
||||
somewhere internally in axum ([#1248])
|
||||
- **added:** Add `ServiceExt` with methods for turning any `Service` into a
|
||||
`MakeService` similarly to `Router::into_make_service` ([#1302])
|
||||
|
||||
[#1077]: https://github.com/tokio-rs/axum/pull/1077
|
||||
[#1086]: https://github.com/tokio-rs/axum/pull/1086
|
||||
|
@ -375,6 +377,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[#1248]: https://github.com/tokio-rs/axum/pull/1248
|
||||
[#1272]: https://github.com/tokio-rs/axum/pull/1272
|
||||
[#1301]: https://github.com/tokio-rs/axum/pull/1301
|
||||
[#1302]: https://github.com/tokio-rs/axum/pull/1302
|
||||
[#924]: https://github.com/tokio-rs/axum/pull/924
|
||||
|
||||
# 0.5.15 (9. August, 2022)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
- [Routing to services/middleware and backpressure](#routing-to-servicesmiddleware-and-backpressure)
|
||||
- [Accessing state in middleware](#accessing-state-in-middleware)
|
||||
- [Passing state from middleware to handlers](#passing-state-from-middleware-to-handlers)
|
||||
- [Rewriting request URI in middleware](#rewriting-request-uri-in-middleware)
|
||||
|
||||
# Intro
|
||||
|
||||
|
@ -557,6 +558,47 @@ let app = Router::new()
|
|||
automatically moved to response extensions. You need to manually do that for the
|
||||
extensions you need.
|
||||
|
||||
# Rewriting request URI in middleware
|
||||
|
||||
Middleware added with [`Router::layer`] will run after routing. That means it
|
||||
cannot be used to run middleware that rewrites the request URI. By the time the
|
||||
middleware runs the routing is already done.
|
||||
|
||||
The workaround is to wrap the middleware around the entire `Router` (this works
|
||||
because `Router` implements [`Service`]):
|
||||
|
||||
```rust
|
||||
use tower::Layer;
|
||||
use axum::{
|
||||
Router,
|
||||
ServiceExt, // for `into_make_service`
|
||||
response::Response,
|
||||
middleware::Next,
|
||||
http::Request,
|
||||
};
|
||||
|
||||
async fn rewrite_request_uri<B>(req: Request<B>, next: Next<B>) -> Response {
|
||||
// ...
|
||||
# next.run(req).await
|
||||
}
|
||||
|
||||
// this can be any `tower::Layer`
|
||||
let middleware = axum::middleware::from_fn(rewrite_request_uri);
|
||||
|
||||
let app = Router::new();
|
||||
|
||||
// apply the layer around the whole `Router`
|
||||
// this way the middleware will run before `Router` receives the request
|
||||
let app_with_middleware = middleware.layer(app);
|
||||
|
||||
# async {
|
||||
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
||||
.serve(app_with_middleware.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
# };
|
||||
```
|
||||
|
||||
[`tower`]: https://crates.io/crates/tower
|
||||
[`tower-http`]: https://crates.io/crates/tower-http
|
||||
[tower-guides]: https://github.com/tower-rs/tower/tree/master/guides
|
||||
|
@ -576,3 +618,4 @@ extensions you need.
|
|||
[request extensions]: https://docs.rs/http/latest/http/request/struct.Request.html#method.extensions
|
||||
[Response extensions]: https://docs.rs/http/latest/http/response/struct.Response.html#method.extensions
|
||||
[`State`]: crate::extract::State
|
||||
[`Service`]: tower::Service
|
||||
|
|
|
@ -9,6 +9,11 @@ of routes.
|
|||
Note this differs from [`Handler::layer`](crate::handler::Handler::layer)
|
||||
which adds a middleware to a single handler.
|
||||
|
||||
Middleware added with this method will run _after_ routing and thus cannot be
|
||||
used to rewrite the request URI. See ["Rewriting request URI in
|
||||
middleware"](crate::middleware#rewriting-request-uri-in-middleware) for more
|
||||
details and a workaround.
|
||||
|
||||
# Example
|
||||
|
||||
Adding the [`tower::limit::ConcurrencyLimit`] middleware to a group of
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub(crate) mod request;
|
||||
pub(crate) mod request_parts;
|
||||
pub(crate) mod service;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
43
axum/src/ext_traits/service.rs
Normal file
43
axum/src/ext_traits/service.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use crate::{extract::connect_info::IntoMakeServiceWithConnectInfo, routing::IntoMakeService};
|
||||
use tower_service::Service;
|
||||
|
||||
/// Extension trait that adds additional methods to any [`Service`].
|
||||
pub trait ServiceExt<R>: Service<R> + Sized {
|
||||
/// Convert this service into a [`MakeService`], that is a [`Service`] whose
|
||||
/// response is another service.
|
||||
///
|
||||
/// This is commonly used when applying middleware around an entire [`Router`]. See ["Rewriting
|
||||
/// request URI in middleware"] for more details.
|
||||
///
|
||||
/// [`MakeService`]: tower::make::MakeService
|
||||
/// ["Rewriting request URI in middleware"]: crate::middleware#rewriting-request-uri-in-middleware
|
||||
/// [`Router`]: crate::Router
|
||||
fn into_make_service(self) -> IntoMakeService<Self>;
|
||||
|
||||
/// Convert this service into a [`MakeService`], that will store `C`'s
|
||||
/// associated `ConnectInfo` in a request extension such that [`ConnectInfo`]
|
||||
/// can extract it.
|
||||
///
|
||||
/// This enables extracting things like the client's remote address.
|
||||
/// This is commonly used when applying middleware around an entire [`Router`]. See ["Rewriting
|
||||
/// request URI in middleware"] for more details.
|
||||
///
|
||||
/// [`MakeService`]: tower::make::MakeService
|
||||
/// ["Rewriting request URI in middleware"]: crate::middleware#rewriting-request-uri-in-middleware
|
||||
/// [`Router`]: crate::Router
|
||||
/// [`ConnectInfo`]: crate::extract::connect_info::ConnectInfo
|
||||
fn into_make_service_with_connect_info<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C>;
|
||||
}
|
||||
|
||||
impl<S, R> ServiceExt<R> for S
|
||||
where
|
||||
S: Service<R> + Sized,
|
||||
{
|
||||
fn into_make_service(self) -> IntoMakeService<Self> {
|
||||
IntoMakeService::new(self)
|
||||
}
|
||||
|
||||
fn into_make_service_with_connect_info<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C> {
|
||||
IntoMakeServiceWithConnectInfo::new(self)
|
||||
}
|
||||
}
|
|
@ -486,4 +486,6 @@ pub use axum_core::{BoxError, Error};
|
|||
#[cfg(feature = "macros")]
|
||||
pub use axum_macros::debug_handler;
|
||||
|
||||
pub use self::ext_traits::{request::RequestExt, request_parts::RequestPartsExt};
|
||||
pub use self::ext_traits::{
|
||||
request::RequestExt, request_parts::RequestPartsExt, service::ServiceExt,
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue