Implement OptionalFromRequestParts for Path<T>

… and deprecate OptionalPath.
This commit is contained in:
Jonas Platte 2023-12-30 22:54:24 +01:00
parent 265e65a783
commit a654c89200
3 changed files with 40 additions and 12 deletions

View file

@ -19,7 +19,9 @@ mod query;
#[cfg(feature = "multipart")]
pub mod multipart;
pub use self::{cached::Cached, optional_path::OptionalPath, with_rejection::WithRejection};
#[allow(deprecated)]
pub use self::optional_path::OptionalPath;
pub use self::{cached::Cached, with_rejection::WithRejection};
#[cfg(feature = "cookie")]
pub use self::cookie::CookieJar;

View file

@ -1,6 +1,6 @@
use axum::{
async_trait,
extract::{path::ErrorKind, rejection::PathRejection, FromRequestParts, Path},
extract::{rejection::PathRejection, FromRequestParts, Path},
RequestPartsExt,
};
use serde::de::DeserializeOwned;
@ -32,9 +32,11 @@ use serde::de::DeserializeOwned;
/// .route("/blog/:page", get(render_blog));
/// # let app: Router = app;
/// ```
#[deprecated = "Use Option<Path<_>> instead"]
#[derive(Debug)]
pub struct OptionalPath<T>(pub Option<T>);
#[allow(deprecated)]
#[async_trait]
impl<T, S> FromRequestParts<S> for OptionalPath<T>
where
@ -47,19 +49,15 @@ where
parts: &mut http::request::Parts,
_: &S,
) -> Result<Self, Self::Rejection> {
match parts.extract::<Path<T>>().await {
Ok(Path(params)) => Ok(Self(Some(params))),
Err(PathRejection::FailedToDeserializePathParams(e))
if matches!(e.kind(), ErrorKind::WrongNumberOfParameters { got: 0, .. }) =>
{
Ok(Self(None))
}
Err(e) => Err(e),
}
parts
.extract::<Option<Path<T>>>()
.await
.map(|opt| Self(opt.map(|Path(x)| x)))
}
}
#[cfg(test)]
#[allow(deprecated)]
mod tests {
use std::num::NonZeroU32;

View file

@ -9,7 +9,11 @@ use crate::{
util::PercentDecodedStr,
};
use async_trait::async_trait;
use axum_core::response::{IntoResponse, Response};
use axum_core::{
extract::OptionalFromRequestParts,
response::{IntoResponse, Response},
RequestPartsExt as _,
};
use http::{request::Parts, StatusCode};
use serde::de::DeserializeOwned;
use std::{fmt, sync::Arc};
@ -178,6 +182,30 @@ where
}
}
#[async_trait]
impl<T, S> OptionalFromRequestParts<S> for Path<T>
where
T: DeserializeOwned + Send + 'static,
S: Send + Sync,
{
type Rejection = PathRejection;
async fn from_request_parts(
parts: &mut Parts,
_state: &S,
) -> Result<Option<Self>, Self::Rejection> {
match parts.extract::<Self>().await {
Ok(Self(params)) => Ok(Some(Self(params))),
Err(PathRejection::FailedToDeserializePathParams(e))
if matches!(e.kind(), ErrorKind::WrongNumberOfParameters { got: 0, .. }) =>
{
Ok(None)
}
Err(e) => Err(e),
}
}
}
// this wrapper type is used as the deserializer error to hide the `serde::de::Error` impl which
// would otherwise be public if we used `ErrorKind` as the error directly
#[derive(Debug)]