From 8cd9c478fe8756680e8e5b5c5f8810ab455f1c70 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 3 Jan 2022 15:37:40 +0100 Subject: [PATCH] Document passing state to handlers via closure captures (#683) --- axum/src/lib.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/axum/src/lib.rs b/axum/src/lib.rs index 364ee095..e7cdb9fc 100644 --- a/axum/src/lib.rs +++ b/axum/src/lib.rs @@ -227,9 +227,17 @@ //! # Sharing state with handlers //! //! It is common to share some state between handlers for example to share a -//! pool of database connections or clients to other services. That can be done -//! using the [`AddExtension`] middleware (applied with [`AddExtensionLayer`]) -//! and the [`Extension`](crate::extract::Extension) extractor: +//! pool of database connections or clients to other services. +//! +//! The two most common ways of doing that is: +//! - Using request extensions +//! - Using closure captures +//! +//! ## Using request extensions +//! +//! The easiest way to extract state in handlers is using [`AddExtension`] +//! middleware (applied with [`AddExtensionLayer`]) and the +//! [`Extension`](crate::extract::Extension) extractor: //! //! ```rust,no_run //! use axum::{ @@ -260,6 +268,68 @@ //! # }; //! ``` //! +//! The downside to this approach is that you'll get runtime errors +//! (specifically a `500 Internal Server Error` response) if you try and extract +//! an extension that doesn't exist, perhaps because you forgot add the +//! middleware or because you're extracting the wrong type. +//! +//! ## Using closure captures +//! +//! State can also be passed directly to handlers using closure captures: +//! +//! ```rust,no_run +//! use axum::{ +//! AddExtensionLayer, +//! Json, +//! extract::{Extension, Path}, +//! routing::{get, post}, +//! Router, +//! }; +//! use std::sync::Arc; +//! use serde::Deserialize; +//! +//! struct State { +//! // ... +//! } +//! +//! let shared_state = Arc::new(State { /* ... */ }); +//! +//! let app = Router::new() +//! .route( +//! "/users", +//! post({ +//! let shared_state = Arc::clone(&shared_state); +//! move |body| create_user(body, Arc::clone(&shared_state)) +//! }), +//! ) +//! .route( +//! "/users/:id", +//! get({ +//! let shared_state = Arc::clone(&shared_state); +//! move |path| get_user(path, Arc::clone(&shared_state)) +//! }), +//! ); +//! +//! async fn get_user(Path(user_id): Path, state: Arc) { +//! // ... +//! } +//! +//! async fn create_user(Json(payload): Json, state: Arc) { +//! // ... +//! } +//! +//! #[derive(Deserialize)] +//! struct CreateUserPayload { +//! // ... +//! } +//! # async { +//! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); +//! # }; +//! ``` +//! +//! The downside to this approach is that its a little more verbose than using +//! extensions. +//! //! # Building integrations for axum //! //! Libraries authors that want to provide [`FromRequest`] or [`IntoResponse`] implementations