mirror of
https://github.com/tokio-rs/axum.git
synced 2025-03-19 21:49:04 +01:00
axum-extra/query: Use rejection macros for QueryRejection
(#3122)
This commit is contained in:
parent
28d8d9b747
commit
5f82540cc1
1 changed files with 26 additions and 95 deletions
|
@ -1,11 +1,8 @@
|
||||||
use axum::{
|
use axum::extract::FromRequestParts;
|
||||||
extract::FromRequestParts,
|
use axum_core::__composite_rejection as composite_rejection;
|
||||||
response::{IntoResponse, Response},
|
use axum_core::__define_rejection as define_rejection;
|
||||||
Error,
|
use http::request::Parts;
|
||||||
};
|
|
||||||
use http::{request::Parts, StatusCode};
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
/// Extractor that deserializes query strings into some type.
|
/// Extractor that deserializes query strings into some type.
|
||||||
///
|
///
|
||||||
|
@ -93,63 +90,27 @@ where
|
||||||
let deserializer =
|
let deserializer =
|
||||||
serde_html_form::Deserializer::new(form_urlencoded::parse(query.as_bytes()));
|
serde_html_form::Deserializer::new(form_urlencoded::parse(query.as_bytes()));
|
||||||
let value = serde_path_to_error::deserialize(deserializer)
|
let value = serde_path_to_error::deserialize(deserializer)
|
||||||
.map_err(|err| QueryRejection::FailedToDeserializeQueryString(Error::new(err)))?;
|
.map_err(FailedToDeserializeQueryString::from_err)?;
|
||||||
Ok(Query(value))
|
Ok(Query(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
axum_core::__impl_deref!(Query);
|
axum_core::__impl_deref!(Query);
|
||||||
|
|
||||||
/// Rejection used for [`Query`].
|
define_rejection! {
|
||||||
///
|
#[status = BAD_REQUEST]
|
||||||
/// Contains one variant for each way the [`Query`] extractor can fail.
|
#[body = "Failed to deserialize query string"]
|
||||||
#[derive(Debug)]
|
/// Rejection type used if the [`Query`] extractor is unable to
|
||||||
#[non_exhaustive]
|
/// deserialize the query string into the target type.
|
||||||
#[cfg(feature = "query")]
|
pub struct FailedToDeserializeQueryString(Error);
|
||||||
pub enum QueryRejection {
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
FailedToDeserializeQueryString(Error),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueryRejection {
|
composite_rejection! {
|
||||||
/// Get the status code used for this rejection.
|
/// Rejection used for [`Query`].
|
||||||
pub fn status(&self) -> StatusCode {
|
///
|
||||||
match self {
|
/// Contains one variant for each way the [`Query`] extractor can fail.
|
||||||
Self::FailedToDeserializeQueryString(_) => StatusCode::BAD_REQUEST,
|
pub enum QueryRejection {
|
||||||
}
|
FailedToDeserializeQueryString,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoResponse for QueryRejection {
|
|
||||||
fn into_response(self) -> Response {
|
|
||||||
let status = self.status();
|
|
||||||
match self {
|
|
||||||
Self::FailedToDeserializeQueryString(inner) => {
|
|
||||||
let body = format!("Failed to deserialize query string: {inner}");
|
|
||||||
axum_core::__log_rejection!(
|
|
||||||
rejection_type = Self,
|
|
||||||
body_text = body,
|
|
||||||
status = status,
|
|
||||||
);
|
|
||||||
(status, body).into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for QueryRejection {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::FailedToDeserializeQueryString(inner) => inner.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for QueryRejection {
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
||||||
match self {
|
|
||||||
Self::FailedToDeserializeQueryString(inner) => Some(inner),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,9 +168,8 @@ where
|
||||||
if let Some(query) = parts.uri.query() {
|
if let Some(query) = parts.uri.query() {
|
||||||
let deserializer =
|
let deserializer =
|
||||||
serde_html_form::Deserializer::new(form_urlencoded::parse(query.as_bytes()));
|
serde_html_form::Deserializer::new(form_urlencoded::parse(query.as_bytes()));
|
||||||
let value = serde_path_to_error::deserialize(deserializer).map_err(|err| {
|
let value = serde_path_to_error::deserialize(deserializer)
|
||||||
OptionalQueryRejection::FailedToDeserializeQueryString(Error::new(err))
|
.map_err(FailedToDeserializeQueryString::from_err)?;
|
||||||
})?;
|
|
||||||
Ok(OptionalQuery(Some(value)))
|
Ok(OptionalQuery(Some(value)))
|
||||||
} else {
|
} else {
|
||||||
Ok(OptionalQuery(None))
|
Ok(OptionalQuery(None))
|
||||||
|
@ -233,42 +193,12 @@ impl<T> std::ops::DerefMut for OptionalQuery<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rejection used for [`OptionalQuery`].
|
composite_rejection! {
|
||||||
///
|
/// Rejection used for [`OptionalQuery`].
|
||||||
/// Contains one variant for each way the [`OptionalQuery`] extractor can fail.
|
///
|
||||||
#[derive(Debug)]
|
/// Contains one variant for each way the [`OptionalQuery`] extractor can fail.
|
||||||
#[non_exhaustive]
|
pub enum OptionalQueryRejection {
|
||||||
#[cfg(feature = "query")]
|
FailedToDeserializeQueryString,
|
||||||
pub enum OptionalQueryRejection {
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
FailedToDeserializeQueryString(Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoResponse for OptionalQueryRejection {
|
|
||||||
fn into_response(self) -> Response {
|
|
||||||
match self {
|
|
||||||
Self::FailedToDeserializeQueryString(inner) => (
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
format!("Failed to deserialize query string: {inner}"),
|
|
||||||
)
|
|
||||||
.into_response(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for OptionalQueryRejection {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::FailedToDeserializeQueryString(inner) => inner.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for OptionalQueryRejection {
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
||||||
match self {
|
|
||||||
Self::FailedToDeserializeQueryString(inner) => Some(inner),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +209,7 @@ mod tests {
|
||||||
use axum::routing::{get, post};
|
use axum::routing::{get, post};
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use http::header::CONTENT_TYPE;
|
use http::header::CONTENT_TYPE;
|
||||||
|
use http::StatusCode;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
Loading…
Add table
Reference in a new issue