From 1ed2ffa7b9f66b27ef35cb6df588a2243d0e99e6 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 19 Dec 2024 22:53:39 +0100 Subject: [PATCH 1/3] Move tokio-tungstenite changelog entry to the right file --- axum-extra/CHANGELOG.md | 4 ---- axum/CHANGELOG.md | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/axum-extra/CHANGELOG.md b/axum-extra/CHANGELOG.md index 0a1f7523e6..5e460a0ae3 100644 --- a/axum-extra/CHANGELOG.md +++ b/axum-extra/CHANGELOG.md @@ -7,12 +7,8 @@ and this project adheres to [Semantic Versioning]. # Unreleased -- **breaking:** `axum::extract::ws::Message` now uses `Bytes` in place of `Vec`, - and a new `Utf8Bytes` type in place of `String`, for its variants ([#3078]) -- **changed:** Upgraded `tokio-tungstenite` to 0.26 ([#3078]) - **changed:** Query/Form: Use `serde_path_to_error` to report fields that failed to parse ([#3081]) -[#3078]: https://github.com/tokio-rs/axum/pull/3078 [#3081]: https://github.com/tokio-rs/axum/pull/3081 # 0.10.0 diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index 5301ebf51a..b11ba1cb47 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -7,8 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Unreleased +- **breaking:** `axum::extract::ws::Message` now uses `Bytes` in place of `Vec`, + and a new `Utf8Bytes` type in place of `String`, for its variants ([#3078]) +- **changed:** Upgraded `tokio-tungstenite` to 0.26 ([#3078]) - **changed:** Query/Form: Use `serde_path_to_error` to report fields that failed to parse ([#3081]) +[#3078]: https://github.com/tokio-rs/axum/pull/3078 [#3081]: https://github.com/tokio-rs/axum/pull/3081 # 0.8.0 From 50a35135b2df32293de06596a41afcc2dc6a6450 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 19 Dec 2024 21:07:39 +0100 Subject: [PATCH 2/3] Un-deprecate OptionalQuery --- axum-extra/src/extract/mod.rs | 1 - axum-extra/src/extract/query.rs | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/axum-extra/src/extract/mod.rs b/axum-extra/src/extract/mod.rs index f858338d9c..f14460f712 100644 --- a/axum-extra/src/extract/mod.rs +++ b/axum-extra/src/extract/mod.rs @@ -41,7 +41,6 @@ pub use self::cookie::SignedCookieJar; pub use self::form::{Form, FormRejection}; #[cfg(feature = "query")] -#[allow(deprecated)] pub use self::query::OptionalQuery; #[cfg(feature = "query")] pub use self::query::{OptionalQueryRejection, Query, QueryRejection}; diff --git a/axum-extra/src/extract/query.rs b/axum-extra/src/extract/query.rs index 489fc1c7d4..2cab133ce5 100644 --- a/axum-extra/src/extract/query.rs +++ b/axum-extra/src/extract/query.rs @@ -181,8 +181,8 @@ impl std::error::Error for QueryRejection { } /// Extractor that deserializes query strings into `None` if no query parameters are present. -/// Otherwise behaviour is identical to [`Query`] /// +/// Otherwise behaviour is identical to [`Query`]. /// `T` is expected to implement [`serde::Deserialize`]. /// /// # Example @@ -220,11 +220,9 @@ impl std::error::Error for QueryRejection { /// /// [example]: https://github.com/tokio-rs/axum/blob/main/examples/query-params-with-empty-strings/src/main.rs #[cfg_attr(docsrs, doc(cfg(feature = "query")))] -#[deprecated = "Use Option> instead"] #[derive(Debug, Clone, Copy, Default)] pub struct OptionalQuery(pub Option); -#[allow(deprecated)] impl FromRequestParts for OptionalQuery where T: DeserializeOwned, @@ -246,7 +244,6 @@ where } } -#[allow(deprecated)] impl std::ops::Deref for OptionalQuery { type Target = Option; @@ -256,7 +253,6 @@ impl std::ops::Deref for OptionalQuery { } } -#[allow(deprecated)] impl std::ops::DerefMut for OptionalQuery { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { @@ -304,7 +300,6 @@ impl std::error::Error for OptionalQueryRejection { } #[cfg(test)] -#[allow(deprecated)] mod tests { use super::*; use crate::test_helpers::*; From 2f1fd5b4e7eb765f60c43ee3f65dd381f383fbd1 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 19 Dec 2024 21:09:15 +0100 Subject: [PATCH 3/3] Remove OptionalFromRequestParts impl for Query --- axum-extra/CHANGELOG.md | 2 ++ axum-extra/src/extract/query.rs | 38 +-------------------------------- axum/CHANGELOG.md | 2 ++ axum/src/docs/extract.md | 10 +-------- axum/src/extract/query.rs | 38 +-------------------------------- 5 files changed, 7 insertions(+), 83 deletions(-) diff --git a/axum-extra/CHANGELOG.md b/axum-extra/CHANGELOG.md index 5e460a0ae3..cf2279714c 100644 --- a/axum-extra/CHANGELOG.md +++ b/axum-extra/CHANGELOG.md @@ -7,9 +7,11 @@ and this project adheres to [Semantic Versioning]. # Unreleased +- **breaking:** Remove `OptionalFromRequestParts` impl for `Query` ([#3088]) - **changed:** Query/Form: Use `serde_path_to_error` to report fields that failed to parse ([#3081]) [#3081]: https://github.com/tokio-rs/axum/pull/3081 +[#3088]: https://github.com/tokio-rs/axum/pull/3088 # 0.10.0 diff --git a/axum-extra/src/extract/query.rs b/axum-extra/src/extract/query.rs index 2cab133ce5..7bd023cf06 100644 --- a/axum-extra/src/extract/query.rs +++ b/axum-extra/src/extract/query.rs @@ -1,5 +1,5 @@ use axum::{ - extract::{FromRequestParts, OptionalFromRequestParts}, + extract::FromRequestParts, response::{IntoResponse, Response}, Error, }; @@ -18,19 +18,6 @@ use std::fmt; /// with the `multiple` attribute. Those values can be collected into a `Vec` or other sequential /// container. /// -/// # `Option>` behavior -/// -/// If `Query` itself is used as an extractor and there is no query string in -/// the request URL, `T`'s `Deserialize` implementation is called on an empty -/// string instead. -/// -/// You can avoid this by using `Option>`, which gives you `None` in -/// the case that there is no query string in the request URL. -/// -/// Note that an empty query string is not the same as no query string, that is -/// `https://example.org/` and `https://example.org/?` are not treated the same -/// in this case. -/// /// # Example /// /// ```rust,no_run @@ -111,29 +98,6 @@ where } } -impl OptionalFromRequestParts for Query -where - T: DeserializeOwned, - S: Send + Sync, -{ - type Rejection = QueryRejection; - - async fn from_request_parts( - parts: &mut Parts, - _state: &S, - ) -> Result, Self::Rejection> { - if let Some(query) = parts.uri.query() { - let deserializer = - serde_html_form::Deserializer::new(form_urlencoded::parse(query.as_bytes())); - let value = serde_path_to_error::deserialize(deserializer) - .map_err(|err| QueryRejection::FailedToDeserializeQueryString(Error::new(err)))?; - Ok(Some(Self(value))) - } else { - Ok(None) - } - } -} - axum_core::__impl_deref!(Query); /// Rejection used for [`Query`]. diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index b11ba1cb47..bb3f4a0778 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -9,11 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **breaking:** `axum::extract::ws::Message` now uses `Bytes` in place of `Vec`, and a new `Utf8Bytes` type in place of `String`, for its variants ([#3078]) +- **breaking:** Remove `OptionalFromRequestParts` impl for `Query` ([#3088]) - **changed:** Upgraded `tokio-tungstenite` to 0.26 ([#3078]) - **changed:** Query/Form: Use `serde_path_to_error` to report fields that failed to parse ([#3081]) [#3078]: https://github.com/tokio-rs/axum/pull/3078 [#3081]: https://github.com/tokio-rs/axum/pull/3081 +[#3088]: https://github.com/tokio-rs/axum/pull/3088 # 0.8.0 diff --git a/axum/src/docs/extract.md b/axum/src/docs/extract.md index 20dfe46e9f..ccc67ce090 100644 --- a/axum/src/docs/extract.md +++ b/axum/src/docs/extract.md @@ -108,18 +108,10 @@ struct Pagination { per_page: usize, } -impl Default for Pagination { - fn default() -> Self { - Self { page: 1, per_page: 30 } - } -} - async fn get_user_things( Path(user_id): Path, - pagination: Option>, + Query(pagination): Query, ) { - let Query(pagination) = pagination.unwrap_or_default(); - // ... } # let _: Router = app; diff --git a/axum/src/extract/query.rs b/axum/src/extract/query.rs index 64221afabb..58b7d366e8 100644 --- a/axum/src/extract/query.rs +++ b/axum/src/extract/query.rs @@ -1,4 +1,4 @@ -use super::{rejection::*, FromRequestParts, OptionalFromRequestParts}; +use super::{rejection::*, FromRequestParts}; use http::{request::Parts, Uri}; use serde::de::DeserializeOwned; @@ -6,19 +6,6 @@ use serde::de::DeserializeOwned; /// /// `T` is expected to implement [`serde::Deserialize`]. /// -/// # `Option>` behavior -/// -/// If `Query` itself is used as an extractor and there is no query string in -/// the request URL, `T`'s `Deserialize` implementation is called on an empty -/// string instead. -/// -/// You can avoid this by using `Option>`, which gives you `None` in -/// the case that there is no query string in the request URL. -/// -/// Note that an empty query string is not the same as no query string, that is -/// `https://example.org/` and `https://example.org/?` are not treated the same -/// in this case. -/// /// # Examples /// /// ```rust,no_run @@ -75,29 +62,6 @@ where } } -impl OptionalFromRequestParts for Query -where - T: DeserializeOwned, - S: Send + Sync, -{ - type Rejection = QueryRejection; - - async fn from_request_parts( - parts: &mut Parts, - _state: &S, - ) -> Result, Self::Rejection> { - if let Some(query) = parts.uri.query() { - let deserializer = - serde_urlencoded::Deserializer::new(form_urlencoded::parse(query.as_bytes())); - let value = serde_path_to_error::deserialize(deserializer) - .map_err(FailedToDeserializeQueryString::from_err)?; - Ok(Some(Self(value))) - } else { - Ok(None) - } - } -} - impl Query where T: DeserializeOwned,