From c8276951b08898bb280aac2c47907a7d8d0e24e4 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Fri, 15 May 2026 12:46:49 +0200 Subject: [PATCH] feat: Add `RawPathParams::from_request_extensions` (#3757) --- axum/CHANGELOG.md | 2 ++ axum/src/extract/path/mod.rs | 34 +++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index dd3cead3..ca9099fd 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 tasks are spawned, enabling use cases like tracing and telemetry instrumentation ([#3704]) - **added:** `IntoResponseParts` impl for `Redirect`, allowing it to be combined with a body in a response tuple ([#3721]) +- **added:** Add `RawPathParams::from_request_extensions` ([#3757]) - **changed:** `serve` has an additional generic argument and can now work with any response body type, not just `axum::body::Body` ([#3205]) - **changed:** `Redirect` constructors now accept any `impl Into` ([#3635]) @@ -37,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#3702]: https://github.com/tokio-rs/axum/pull/3702 [#3721]: https://github.com/tokio-rs/axum/pull/3721 [#3742]: https://github.com/tokio-rs/axum/pull/3742 +[#3757]: https://github.com/tokio-rs/axum/pull/3757 # 0.8.9 diff --git a/axum/src/extract/path/mod.rs b/axum/src/extract/path/mod.rs index ffc345be..61bbef9b 100644 --- a/axum/src/extract/path/mod.rs +++ b/axum/src/extract/path/mod.rs @@ -13,7 +13,7 @@ use axum_core::{ response::{IntoResponse, Response}, RequestPartsExt as _, }; -use http::{request::Parts, StatusCode}; +use http::{request::Parts, Extensions, StatusCode}; use serde_core::de::DeserializeOwned; use std::{fmt, sync::Arc}; @@ -507,24 +507,28 @@ where type Rejection = RawPathParamsRejection; async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { - let params = match parts.extensions.get::() { - Some(UrlParams::Params(params)) => params, - Some(UrlParams::InvalidUtf8InPathParam { key }) => { - return Err(InvalidUtf8InPathParam { - key: Arc::clone(key), - } - .into()); - } - None => { - return Err(MissingPathParams.into()); - } - }; - - Ok(Self(params.clone())) + Self::from_request_extensions(&parts.extensions) } } impl RawPathParams { + /// Construct a `RawPathParams` from request extensions. + /// + /// Most users should prefer to use the `FromRequestParts` impl but special cases may require + /// extracting `RawPathParams` outside of an async context. + pub fn from_request_extensions( + extensions: &Extensions, + ) -> Result { + match extensions.get::() { + Some(UrlParams::Params(params)) => Ok(Self(params.clone())), + Some(UrlParams::InvalidUtf8InPathParam { key }) => Err(InvalidUtf8InPathParam { + key: Arc::clone(key), + } + .into()), + None => Err(MissingPathParams.into()), + } + } + /// Get an iterator over the path parameters. #[must_use] pub fn iter(&self) -> RawPathParamsIter<'_> {