This commit is contained in:
gengteng
2023-06-06 11:35:11 +08:00
parent d61815e264
commit 9de1b42ce4
2 changed files with 72 additions and 66 deletions

View File

@@ -24,5 +24,4 @@ edition = "2021"
[dependencies] [dependencies]
axum = "0.6.18" axum = "0.6.18"
serde = "1.0.163"
validator = "0.16.0" validator = "0.16.0"

View File

@@ -1,11 +1,9 @@
use axum::body::HttpBody;
use axum::extract::rejection::{FormRejection, JsonRejection, PathRejection, QueryRejection}; use axum::extract::rejection::{FormRejection, JsonRejection, PathRejection, QueryRejection};
use axum::extract::{FromRequest, FromRequestParts, Path, Query}; use axum::extract::{FromRequest, FromRequestParts, Path, Query};
use axum::http::request::Parts; use axum::http::request::Parts;
use axum::http::{Request, StatusCode}; use axum::http::{Request, StatusCode};
use axum::response::{IntoResponse, Response}; use axum::response::{IntoResponse, Response};
use axum::{async_trait, BoxError, Form, Json}; use axum::{async_trait, Form, Json};
use serde::de::DeserializeOwned;
use validator::{Validate, ValidationErrors}; use validator::{Validate, ValidationErrors};
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
@@ -39,86 +37,95 @@ impl From<JsonRejection> for ValidRejection<JsonRejection> {
} }
} }
#[async_trait]
impl<T, S, B> FromRequest<S, B> for Valid<Json<T>>
where
T: DeserializeOwned + Validate,
B: HttpBody + Send + 'static,
B::Data: Send,
B::Error: Into<BoxError>,
S: Send + Sync,
{
type Rejection = ValidRejection<JsonRejection>;
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
let json = Json::<T>::from_request(req, state).await?;
json.0.validate()?;
Ok(Valid(json))
}
}
impl From<QueryRejection> for ValidRejection<QueryRejection> { impl From<QueryRejection> for ValidRejection<QueryRejection> {
fn from(value: QueryRejection) -> Self { fn from(value: QueryRejection) -> Self {
Self::Inner(value) Self::Inner(value)
} }
} }
#[async_trait]
impl<T, S> FromRequestParts<S> for Valid<Query<T>>
where
T: DeserializeOwned + Validate,
S: Send + Sync,
{
type Rejection = ValidRejection<QueryRejection>;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let query = Query::<T>::from_request_parts(parts, state).await?;
query.validate()?;
Ok(Valid(query))
}
}
impl From<PathRejection> for ValidRejection<PathRejection> { impl From<PathRejection> for ValidRejection<PathRejection> {
fn from(value: PathRejection) -> Self { fn from(value: PathRejection) -> Self {
Self::Inner(value) Self::Inner(value)
} }
} }
#[async_trait]
impl<T, S> FromRequestParts<S> for Valid<Path<T>>
where
T: DeserializeOwned + Validate + Send,
S: Send + Sync,
{
type Rejection = ValidRejection<PathRejection>;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let path = Path::<T>::from_request_parts(parts, state).await?;
path.validate()?;
Ok(Valid(path))
}
}
impl From<FormRejection> for ValidRejection<FormRejection> { impl From<FormRejection> for ValidRejection<FormRejection> {
fn from(value: FormRejection) -> Self { fn from(value: FormRejection) -> Self {
Self::Inner(value) Self::Inner(value)
} }
} }
#[async_trait] pub trait Inner0 {
impl<T, S, B> FromRequest<S, B> for Valid<Form<T>> type Inner: Validate;
where type Rejection;
T: DeserializeOwned + Validate, fn inner0_ref(&self) -> &Self::Inner;
B: HttpBody + Send + 'static, }
B::Data: Send,
B::Error: Into<BoxError>,
S: Send + Sync,
{
type Rejection = ValidRejection<FormRejection>;
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { impl<T: Validate> Inner0 for Json<T> {
let form = Form::<T>::from_request(req, state).await?; type Inner = T;
form.validate()?; type Rejection = JsonRejection;
Ok(Valid(form)) fn inner0_ref(&self) -> &T {
&self.0
}
}
impl<T: Validate> Inner0 for Form<T> {
type Inner = T;
type Rejection = FormRejection;
fn inner0_ref(&self) -> &T {
&self.0
}
}
impl<T: Validate> Inner0 for Query<T> {
type Inner = T;
type Rejection = QueryRejection;
fn inner0_ref(&self) -> &T {
&self.0
}
}
impl<T: Validate> Inner0 for Path<T> {
type Inner = T;
type Rejection = QueryRejection;
fn inner0_ref(&self) -> &T {
&self.0
}
}
#[async_trait]
impl<S, B, T> FromRequest<S, B> for Valid<T>
where
S: Send + Sync + 'static,
B: Send + Sync + 'static,
T: Inner0 + FromRequest<S, B>,
T::Inner: Validate,
<T as Inner0>::Rejection: IntoResponse,
ValidRejection<<T as Inner0>::Rejection>: From<<T as FromRequest<S, B>>::Rejection>,
{
type Rejection = ValidRejection<<T as Inner0>::Rejection>;
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
let valid = T::from_request(req, state).await?;
valid.inner0_ref().validate()?;
Ok(Valid(valid))
}
}
#[async_trait]
impl<S, T> FromRequestParts<S> for Valid<T>
where
S: Send + Sync + 'static,
T: Inner0 + FromRequestParts<S>,
T::Inner: Validate,
<T as Inner0>::Rejection: IntoResponse,
ValidRejection<<T as Inner0>::Rejection>: From<<T as FromRequestParts<S>>::Rejection>,
{
type Rejection = ValidRejection<<T as Inner0>::Rejection>;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let valid = T::from_request_parts(parts, state).await?;
valid.inner0_ref().validate()?;
Ok(Valid(valid))
} }
} }