Skip to content

Commit

Permalink
Remove OptionalFromRequestParts impl for Query
Browse files Browse the repository at this point in the history
  • Loading branch information
jplatte committed Dec 19, 2024
1 parent 48ef9e3 commit 3ec8de3
Show file tree
Hide file tree
Showing 5 changed files with 11 additions and 79 deletions.
4 changes: 4 additions & 0 deletions axum-extra/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning].

# Unreleased

- **breaking:** Remove `OptionalFromRequestParts` impl for `Query` ([#3088])

[#3088]: https://github.com/tokio-rs/axum/pull/3088

# 0.10.0

## rc.1
Expand Down
36 changes: 1 addition & 35 deletions axum-extra/src/extract/query.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use axum::{
extract::{FromRequestParts, OptionalFromRequestParts},
extract::FromRequestParts,
response::{IntoResponse, Response},
Error,
};
Expand All @@ -18,19 +18,6 @@ use std::fmt;
/// with the `multiple` attribute. Those values can be collected into a `Vec` or other sequential
/// container.
///
/// # `Option<Query<T>>` behavior
///
/// If `Query<T>` 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<Query<T>>`, 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
Expand Down Expand Up @@ -109,27 +96,6 @@ where
}
}

impl<T, S> OptionalFromRequestParts<S> for Query<T>
where
T: DeserializeOwned,
S: Send + Sync,
{
type Rejection = QueryRejection;

async fn from_request_parts(
parts: &mut Parts,
_state: &S,
) -> Result<Option<Self>, Self::Rejection> {
if let Some(query) = parts.uri.query() {
let value = serde_html_form::from_str(query)
.map_err(|err| QueryRejection::FailedToDeserializeQueryString(Error::new(err)))?;
Ok(Some(Self(value)))
} else {
Ok(None)
}
}
}

axum_core::__impl_deref!(Query);

/// Rejection used for [`Query`].
Expand Down
4 changes: 4 additions & 0 deletions axum/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

# Unreleased

- **breaking:** Remove `OptionalFromRequestParts` impl for `Query` ([#3088])

[#3088]: https://github.com/tokio-rs/axum/pull/3088

# 0.8.0

## rc.1
Expand Down
10 changes: 1 addition & 9 deletions axum/src/docs/extract.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<Uuid>,
pagination: Option<Query<Pagination>>,
Query(pagination): Query<Pagination>,
) {
let Query(pagination) = pagination.unwrap_or_default();
// ...
}
# let _: Router = app;
Expand Down
36 changes: 1 addition & 35 deletions axum/src/extract/query.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
use super::{rejection::*, FromRequestParts, OptionalFromRequestParts};
use super::{rejection::*, FromRequestParts};
use http::{request::Parts, Uri};
use serde::de::DeserializeOwned;

/// Extractor that deserializes query strings into some type.
///
/// `T` is expected to implement [`serde::Deserialize`].
///
/// # `Option<Query<T>>` behavior
///
/// If `Query<T>` 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<Query<T>>`, 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
Expand Down Expand Up @@ -75,27 +62,6 @@ where
}
}

impl<T, S> OptionalFromRequestParts<S> for Query<T>
where
T: DeserializeOwned,
S: Send + Sync,
{
type Rejection = QueryRejection;

async fn from_request_parts(
parts: &mut Parts,
_state: &S,
) -> Result<Option<Self>, Self::Rejection> {
if let Some(query) = parts.uri.query() {
let value = serde_urlencoded::from_str(query)
.map_err(FailedToDeserializeQueryString::from_err)?;
Ok(Some(Self(value)))
} else {
Ok(None)
}
}
}

impl<T> Query<T>
where
T: DeserializeOwned,
Expand Down

0 comments on commit 3ec8de3

Please sign in to comment.