mirror of
https://github.com/tokio-rs/axum.git
synced 2025-01-05 18:27:07 +01:00
Document sharing state between handler and middleware (#783)
* Fix heading levels * Document passing state from middleware to handlers
This commit is contained in:
parent
49d8fc5093
commit
113a15a713
2 changed files with 64 additions and 2 deletions
|
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- **added:** `middleware::from_fn` for creating middleware from async functions.
|
- **added:** `middleware::from_fn` for creating middleware from async functions.
|
||||||
This previously lived in axum-extra but has been moved to axum ([#719])
|
This previously lived in axum-extra but has been moved to axum ([#719])
|
||||||
|
- **added:** Document sharing state between handler and middleware (#783])
|
||||||
- **breaking:** `sse::Event` now accepts types implementing `AsRef<str>` instead of `Into<String>`
|
- **breaking:** `sse::Event` now accepts types implementing `AsRef<str>` instead of `Into<String>`
|
||||||
as field values.
|
as field values.
|
||||||
- **breaking:** `sse::Event` now panics if a setter method is called twice instead of silently
|
- **breaking:** `sse::Event` now panics if a setter method is called twice instead of silently
|
||||||
|
@ -65,6 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
[#733]: https://github.com/tokio-rs/axum/pull/733
|
[#733]: https://github.com/tokio-rs/axum/pull/733
|
||||||
[#734]: https://github.com/tokio-rs/axum/pull/734
|
[#734]: https://github.com/tokio-rs/axum/pull/734
|
||||||
[#755]: https://github.com/tokio-rs/axum/pull/755
|
[#755]: https://github.com/tokio-rs/axum/pull/755
|
||||||
|
[#783]: https://github.com/tokio-rs/axum/pull/783
|
||||||
|
|
||||||
# 0.4.4 (13. January, 2022)
|
# 0.4.4 (13. January, 2022)
|
||||||
|
|
||||||
|
|
|
@ -191,7 +191,7 @@ You should use these when
|
||||||
- You want to perform a small ad hoc operation, such as adding a header.
|
- You want to perform a small ad hoc operation, such as adding a header.
|
||||||
- You don't intend to publish your middleware as a crate for others to use.
|
- You don't intend to publish your middleware as a crate for others to use.
|
||||||
|
|
||||||
# `tower::Service` and `Pin<Box<dyn Future>>`
|
## `tower::Service` and `Pin<Box<dyn Future>>`
|
||||||
|
|
||||||
For maximum control (and a more low level API) you can write you own middleware
|
For maximum control (and a more low level API) you can write you own middleware
|
||||||
by implementing [`tower::Service`]:
|
by implementing [`tower::Service`]:
|
||||||
|
@ -254,7 +254,7 @@ where
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# `tower::Service` and custom futures
|
## `tower::Service` and custom futures
|
||||||
|
|
||||||
If you're comfortable implementing your own futures (or want to learn it) and
|
If you're comfortable implementing your own futures (or want to learn it) and
|
||||||
need as much control as possible then using `tower::Service` without boxed
|
need as much control as possible then using `tower::Service` without boxed
|
||||||
|
@ -374,6 +374,64 @@ Also note that handlers created from async functions don't care about
|
||||||
backpressure and are always ready. So if you're not using any Tower
|
backpressure and are always ready. So if you're not using any Tower
|
||||||
middleware you don't have to worry about any of this.
|
middleware you don't have to worry about any of this.
|
||||||
|
|
||||||
|
# Sharing state between handlers and middleware
|
||||||
|
|
||||||
|
State can be shared between middleware and handlers using [request extensions]:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use axum::{
|
||||||
|
Router,
|
||||||
|
http::{Request, StatusCode},
|
||||||
|
routing::get,
|
||||||
|
response::IntoResponse,
|
||||||
|
middleware::{self, Next},
|
||||||
|
extract::Extension,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct CurrentUser { /* ... */ }
|
||||||
|
|
||||||
|
async fn auth<B>(mut req: Request<B>, next: Next<B>) -> impl IntoResponse {
|
||||||
|
let auth_header = req.headers()
|
||||||
|
.get(http::header::AUTHORIZATION)
|
||||||
|
.and_then(|header| header.to_str().ok());
|
||||||
|
|
||||||
|
let auth_header = if let Some(auth_header) = auth_header {
|
||||||
|
auth_header
|
||||||
|
} else {
|
||||||
|
return Err(StatusCode::UNAUTHORIZED);
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(current_user) = authorize_current_user(auth_header).await {
|
||||||
|
req.extensions_mut().insert(current_user);
|
||||||
|
Ok(next.run(req).await)
|
||||||
|
} else {
|
||||||
|
Err(StatusCode::UNAUTHORIZED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn authorize_current_user(auth_token: &str) -> Option<CurrentUser> {
|
||||||
|
// ...
|
||||||
|
# unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handler(
|
||||||
|
// extract the current user, set by the middleware
|
||||||
|
Extension(current_user): Extension<CurrentUser>,
|
||||||
|
) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
let app = Router::new()
|
||||||
|
.route("/", get(handler))
|
||||||
|
.route_layer(middleware::from_fn(auth));
|
||||||
|
# let app: Router = app;
|
||||||
|
```
|
||||||
|
|
||||||
|
[Response extensions] can also be used but note that request extensions are not
|
||||||
|
automatically moved to response extensions. You need to manually do that for the
|
||||||
|
extensions you need.
|
||||||
|
|
||||||
[`tower`]: https://crates.io/crates/tower
|
[`tower`]: https://crates.io/crates/tower
|
||||||
[`tower-http`]: https://crates.io/crates/tower-http
|
[`tower-http`]: https://crates.io/crates/tower-http
|
||||||
[tower-guides]: https://github.com/tower-rs/tower/tree/master/guides
|
[tower-guides]: https://github.com/tower-rs/tower/tree/master/guides
|
||||||
|
@ -390,3 +448,5 @@ middleware you don't have to worry about any of this.
|
||||||
[`MethodRouter::layer`]: crate::routing::MethodRouter::layer
|
[`MethodRouter::layer`]: crate::routing::MethodRouter::layer
|
||||||
[`Router::route_layer`]: crate::routing::Router::route_layer
|
[`Router::route_layer`]: crate::routing::Router::route_layer
|
||||||
[`MethodRouter::route_layer`]: crate::routing::MethodRouter::route_layer
|
[`MethodRouter::route_layer`]: crate::routing::MethodRouter::route_layer
|
||||||
|
[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
|
||||||
|
|
Loading…
Reference in a new issue