summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Le Morlec <baptistelemorlec@gmail.com>2024-08-13 23:48:31 +0200
committerGitHub <noreply@github.com>2024-08-13 21:48:31 +0000
commit35c6f11c94ff3b47b2a7506685d4fdb3c1b1acfe (patch)
treed4baaa75072e2dbc166a290eb5c7a245ca8a4912
parent52ae7bb904cc374ad0acdc08ae03760a71d95ac2 (diff)
Add docs on using tokio task_local to share state (#2769)
-rw-r--r--axum/src/lib.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/axum/src/lib.rs b/axum/src/lib.rs
index 94174229..7d0d3802 100644
--- a/axum/src/lib.rs
+++ b/axum/src/lib.rs
@@ -293,6 +293,67 @@
//! The downside to this approach is that it's a little more verbose than using
//! [`State`] or extensions.
//!
+//! ## Using [tokio's `task_local` macro](https://docs.rs/tokio/1/tokio/macro.task_local.html):
+//!
+//! This allows to share state with `IntoResponse` implementations.
+//!
+//! ```rust,no_run
+//! use axum::{
+//! extract::Request,
+//! http::{header, StatusCode},
+//! middleware::{self, Next},
+//! response::{IntoResponse, Response},
+//! routing::get,
+//! Router,
+//! };
+//! use tokio::task_local;
+//!
+//! #[derive(Clone)]
+//! struct CurrentUser {
+//! name: String,
+//! }
+//! task_local! {
+//! pub static USER: CurrentUser;
+//! }
+//!
+//! async fn auth(req: Request, next: Next) -> Result<Response, StatusCode> {
+//! let auth_header = req
+//! .headers()
+//! .get(header::AUTHORIZATION)
+//! .and_then(|header| header.to_str().ok())
+//! .ok_or(StatusCode::UNAUTHORIZED)?;
+//! if let Some(current_user) = authorize_current_user(auth_header).await {
+//! // State is setup here in the middleware
+//! Ok(USER.scope(current_user, next.run(req)).await)
+//! } else {
+//! Err(StatusCode::UNAUTHORIZED)
+//! }
+//! }
+//! async fn authorize_current_user(auth_token: &str) -> Option<CurrentUser> {
+//! Some(CurrentUser {
+//! name: auth_token.to_string(),
+//! })
+//! }
+//!
+//! struct UserResponse;
+//!
+//! impl IntoResponse for UserResponse {
+//! fn into_response(self) -> Response {
+//! // State is accessed here in the IntoResponse implementation
+//! let current_user = USER.with(|u| u.clone());
+//! (StatusCode::OK, current_user.name).into_response()
+//! }
+//! }
+//!
+//! async fn handler() -> UserResponse {
+//! UserResponse
+//! }
+//!
+//! let app: Router = Router::new()
+//! .route("/", get(handler))
+//! .route_layer(middleware::from_fn(auth));
+//! ```
+//!
//! # Building integrations for axum
//!
//! Libraries authors that want to provide [`FromRequest`], [`FromRequestParts`], or