Document sharing state between handler and middleware (#783)

* Fix heading levels

* Document passing state from middleware to handlers
This commit is contained in:
David Pedersen 2022-02-22 16:14:18 +01:00 committed by GitHub
parent 49d8fc5093
commit 113a15a713
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 2 deletions

View file

@ -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.
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>`
as field values.
- **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
[#734]: https://github.com/tokio-rs/axum/pull/734
[#755]: https://github.com/tokio-rs/axum/pull/755
[#783]: https://github.com/tokio-rs/axum/pull/783
# 0.4.4 (13. January, 2022)

View file

@ -191,7 +191,7 @@ You should use these when
- 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.
# `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
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
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
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-http`]: https://crates.io/crates/tower-http
[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
[`Router::route_layer`]: crate::routing::Router::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