refactor: Validified

This commit is contained in:
gengteng
2024-01-06 15:21:01 +08:00
parent 10802a5249
commit 16283fd562
13 changed files with 100 additions and 56 deletions

View File

@@ -28,8 +28,7 @@ features = ["full", "aide"]
axum = { version = "0.7.1", default-features = false } axum = { version = "0.7.1", default-features = false }
garde = { version = "0.16.3", optional = true } garde = { version = "0.16.3", optional = true }
validator = { version = "0.16.1", optional = true} validator = { version = "0.16.1", optional = true}
validify = { version = "=1.0", optional = true } validify = { version = "1.3.0", optional = true}
validify_derive = { version = "=1.0", optional = true }
[dependencies.axum-extra] [dependencies.axum-extra]
version = "0.9.0" version = "0.9.0"
@@ -74,7 +73,7 @@ default = ["basic", "validator"]
basic = ["json", "form", "query"] basic = ["json", "form", "query"]
garde = ["dep:garde"] garde = ["dep:garde"]
validator = ["dep:validator"] validator = ["dep:validator"]
validify = ["dep:validify", "dep:validify_derive"] validify = ["dep:validify"]
json = ["axum/json"] json = ["axum/json"]
form = ["axum/form"] form = ["axum/form"]
query = ["axum/query"] query = ["axum/query"]

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Form<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for Form<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for Form<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = Form<T::Payload>; type PayloadExtractor = Form<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
Form(v) Form(v)
} }
} }

View File

@@ -126,11 +126,11 @@ impl<T> crate::PayloadExtractor for Query<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for Query<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for Query<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = Query<T::Payload>; type PayloadExtractor = Query<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
Query(v) Query(v)
} }
} }

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Form<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for Form<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for Form<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = Form<T::Payload>; type PayloadExtractor = Form<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
Form(v) Form(v)
} }
} }

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Json<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for Json<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for Json<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = Json<T::Payload>; type PayloadExtractor = Json<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
Json(v) Json(v)
} }
} }

View File

@@ -133,10 +133,10 @@ impl<T> crate::PayloadExtractor for MsgPack<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for MsgPack<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for MsgPack<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = MsgPack<T::Payload>; type PayloadExtractor = MsgPack<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
MsgPack(v) MsgPack(v)
} }
} }
@@ -175,10 +175,10 @@ impl<T> crate::PayloadExtractor for MsgPackRaw<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for MsgPackRaw<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for MsgPackRaw<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = MsgPackRaw<T::Payload>; type PayloadExtractor = MsgPackRaw<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
MsgPackRaw(v) MsgPackRaw(v)
} }
} }

View File

@@ -122,11 +122,11 @@ impl<T> crate::PayloadExtractor for Path<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for Path<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for Path<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = Path<T::Payload>; type PayloadExtractor = Path<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
Path(v) Path(v)
} }
} }

View File

@@ -126,11 +126,11 @@ impl<T> crate::PayloadExtractor for Query<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for Query<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for Query<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = Query<T::Payload>; type PayloadExtractor = Query<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
Query(v) Query(v)
} }
} }

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Toml<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for Toml<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for Toml<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = Toml<T::Payload>; type PayloadExtractor = Toml<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
Toml(v) Toml(v)
} }
} }

View File

@@ -15,7 +15,7 @@ use axum::http::request::Parts;
use axum::response::{IntoResponse, Response}; use axum::response::{IntoResponse, Response};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use validify::{Modify, Validate, ValidationErrors, Validify}; use validify::{Modify, Validate, ValidationErrors, ValidifyPayload};
/// # `Validated` data extractor /// # `Validated` data extractor
/// ///
@@ -232,15 +232,15 @@ pub trait PayloadExtractor {
/// ///
pub trait HasValidify: Sized { pub trait HasValidify: Sized {
/// Inner type that can be modified and validated using `validify`. /// Inner type that can be modified and validated using `validify`.
type Validify: Validify; type Validify: ValidifyPayload;
/// Extracts payload from the request, /// Extracts payload from the request,
/// which will be used to construct the `Self::Validify` type /// which will be used to construct the `Self::Validify` type
/// and perform modification and validation on it. /// and perform modification and validation on it.
type PayloadExtractor: PayloadExtractor<Payload = <Self::Validify as Validify>::Payload>; type PayloadExtractor: PayloadExtractor<Payload = <Self::Validify as ValidifyPayload>::Payload>;
/// Re-packages the validified data back into the inner Extractor type. /// Re-packages the validified data back into the inner Extractor type.
fn from_validified(v: Self::Validify) -> Self; fn from_validify(v: Self::Validify) -> Self;
} }
#[async_trait] #[async_trait]
@@ -314,7 +314,6 @@ impl<State, Extractor> FromRequest<State> for Validified<Extractor>
where where
State: Send + Sync, State: Send + Sync,
Extractor: HasValidify, Extractor: HasValidify,
Extractor::Validify: Validify,
Extractor::PayloadExtractor: FromRequest<State>, Extractor::PayloadExtractor: FromRequest<State>,
{ {
type Rejection = type Rejection =
@@ -323,10 +322,10 @@ where
async fn from_request(req: Request, state: &State) -> Result<Self, Self::Rejection> { async fn from_request(req: Request, state: &State) -> Result<Self, Self::Rejection> {
let payload = Extractor::PayloadExtractor::from_request(req, state) let payload = Extractor::PayloadExtractor::from_request(req, state)
.await .await
.map_err(ValidifyRejection::Inner)?; .map_err(ValidifyRejection::Inner)?
Ok(Validified(Extractor::from_validified( .get_payload();
Extractor::Validify::validify(payload.get_payload())?, let validify = Extractor::Validify::validify_from(payload)?;
))) Ok(Validified(Extractor::from_validify(validify)))
} }
} }
@@ -335,7 +334,6 @@ impl<State, Extractor> FromRequestParts<State> for Validified<Extractor>
where where
State: Send + Sync, State: Send + Sync,
Extractor: HasValidify, Extractor: HasValidify,
Extractor::Validify: Validify,
Extractor::PayloadExtractor: FromRequestParts<State>, Extractor::PayloadExtractor: FromRequestParts<State>,
{ {
type Rejection = type Rejection =
@@ -344,10 +342,10 @@ where
async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> { async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> {
let payload = Extractor::PayloadExtractor::from_request_parts(parts, state) let payload = Extractor::PayloadExtractor::from_request_parts(parts, state)
.await .await
.map_err(ValidifyRejection::Inner)?; .map_err(ValidifyRejection::Inner)?
Ok(Validified(Extractor::from_validified( .get_payload();
Extractor::Validify::validify(payload.get_payload())?, let validify = Extractor::Validify::validify_from(payload)?;
))) Ok(Validified(Extractor::from_validify(validify)))
} }
} }
@@ -470,6 +468,7 @@ mod tests {
#[test] #[test]
fn modified_into_response() { fn modified_into_response() {
use validify::Validify;
#[derive(Validify, Serialize)] #[derive(Validify, Serialize)]
struct Data { struct Data {
#[modify(trim)] #[modify(trim)]

View File

@@ -18,15 +18,24 @@ use std::any::type_name;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::ops::Deref; use std::ops::Deref;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use validify::{Modify, Validate, Validify}; use validify::{Modify, Payload, Validate, Validify};
#[derive(Clone, Deserialize, Serialize, Validify, Eq, PartialEq)] #[derive(Debug, Clone, Deserialize, Serialize, Validify, Payload, Eq, PartialEq)]
pub struct ParametersValidify {
#[validate(range(min = 5.0, max = 10.0))]
v0: i32,
#[modify(lowercase)]
#[validate(length(min = 1, max = 10))]
v1: String,
}
#[derive(Clone, Validify, Eq, PartialEq)]
#[cfg_attr(feature = "extra_protobuf", derive(Message))] #[cfg_attr(feature = "extra_protobuf", derive(Message))]
#[cfg_attr( #[cfg_attr(
feature = "typed_multipart", feature = "typed_multipart",
derive(axum_typed_multipart::TryFromMultipart) derive(axum_typed_multipart::TryFromMultipart)
)] )]
pub struct ParametersValidify { pub struct ParametersValidifyWithoutPayload {
#[validate(range(min = 5.0, max = 10.0))] #[validate(range(min = 5.0, max = 10.0))]
#[cfg_attr(feature = "extra_protobuf", prost(int32, tag = "1"))] #[cfg_attr(feature = "extra_protobuf", prost(int32, tag = "1"))]
v0: i32, v0: i32,
@@ -56,6 +65,18 @@ static INVALID_PARAMETERS: Lazy<ParametersValidify> = Lazy::new(|| ParametersVal
v1: String::from("ABCDEFGHIJKLMN"), v1: String::from("ABCDEFGHIJKLMN"),
}); });
static VALID_PARAMETERS_WITHOUT_PAYLOAD: Lazy<ParametersValidifyWithoutPayload> =
Lazy::new(|| ParametersValidifyWithoutPayload {
v0: 5,
v1: String::from("ABCDEFG"),
});
static INVALID_PARAMETERS_WITHOUT_PAYLOAD: Lazy<ParametersValidifyWithoutPayload> =
Lazy::new(|| ParametersValidifyWithoutPayload {
v0: 6,
v1: String::from("ABCDEFGHIJKLMN"),
});
impl ValidTestParameter for ParametersValidify { impl ValidTestParameter for ParametersValidify {
fn valid() -> &'static Self { fn valid() -> &'static Self {
VALID_PARAMETERS.deref() VALID_PARAMETERS.deref()
@@ -70,6 +91,20 @@ impl ValidTestParameter for ParametersValidify {
} }
} }
impl ValidTestParameter for ParametersValidifyWithoutPayload {
fn valid() -> &'static Self {
VALID_PARAMETERS_WITHOUT_PAYLOAD.deref()
}
fn error() -> &'static [(&'static str, &'static str)] {
&[("not_v0_or_v1", "value")]
}
fn invalid() -> &'static Self {
INVALID_PARAMETERS_WITHOUT_PAYLOAD.deref()
}
}
impl HasValidate for ParametersValidify { impl HasValidate for ParametersValidify {
type Validate = ParametersValidify; type Validate = ParametersValidify;
@@ -836,21 +871,21 @@ async fn test_main() -> anyhow::Result<()> {
use axum_extra::protobuf::Protobuf; use axum_extra::protobuf::Protobuf;
// Validated // Validated
test_executor test_executor
.execute::<Protobuf<ParametersValidify>>( .execute::<Protobuf<ParametersValidifyWithoutPayload>>(
Method::POST, Method::POST,
extra_protobuf::route::EXTRA_PROTOBUF, extra_protobuf::route::EXTRA_PROTOBUF,
) )
.await?; .await?;
// Modified // Modified
test_executor test_executor
.execute_modified::<Protobuf<ParametersValidify>>( .execute_modified::<Protobuf<ParametersValidifyWithoutPayload>>(
Method::POST, Method::POST,
extra_protobuf::route::EXTRA_PROTOBUF_MODIFIED, extra_protobuf::route::EXTRA_PROTOBUF_MODIFIED,
) )
.await?; .await?;
// ValidifiedByRef // ValidifiedByRef
test_executor test_executor
.execute::<Protobuf<ParametersValidify>>( .execute::<Protobuf<ParametersValidifyWithoutPayload>>(
Method::POST, Method::POST,
extra_protobuf::route::EXTRA_PROTOBUF_VALIDIFIED_BY_REF, extra_protobuf::route::EXTRA_PROTOBUF_VALIDIFIED_BY_REF,
) )
@@ -1356,7 +1391,10 @@ mod typed_header {
#[cfg(feature = "typed_multipart")] #[cfg(feature = "typed_multipart")]
mod typed_multipart { mod typed_multipart {
use super::{check_modified, check_validated, check_validified, ParametersValidify}; use super::{
check_modified, check_validated, check_validified, ParametersValidify,
ParametersValidifyWithoutPayload,
};
use crate::{Modified, Validated, ValidifiedByRef}; use crate::{Modified, Validated, ValidifiedByRef};
use axum::http::StatusCode; use axum::http::StatusCode;
use axum_typed_multipart::{BaseMultipart, TypedMultipart, TypedMultipartError}; use axum_typed_multipart::{BaseMultipart, TypedMultipart, TypedMultipartError};
@@ -1380,20 +1418,24 @@ mod typed_multipart {
} }
pub(super) async fn extract_typed_multipart( pub(super) async fn extract_typed_multipart(
Validated(TypedMultipart(parameters)): Validated<TypedMultipart<ParametersValidify>>, Validated(TypedMultipart(parameters)): Validated<
TypedMultipart<ParametersValidifyWithoutPayload>,
>,
) -> StatusCode { ) -> StatusCode {
check_validated(&parameters) check_validated(&parameters)
} }
pub(super) async fn extract_typed_multipart_modified( pub(super) async fn extract_typed_multipart_modified(
Modified(TypedMultipart(parameters)): Modified<TypedMultipart<ParametersValidify>>, Modified(TypedMultipart(parameters)): Modified<
TypedMultipart<ParametersValidifyWithoutPayload>,
>,
) -> StatusCode { ) -> StatusCode {
check_modified(&parameters) check_modified(&parameters)
} }
pub(super) async fn extract_typed_multipart_validified_by_ref( pub(super) async fn extract_typed_multipart_validified_by_ref(
ValidifiedByRef(TypedMultipart(parameters)): ValidifiedByRef< ValidifiedByRef(TypedMultipart(parameters)): ValidifiedByRef<
TypedMultipart<ParametersValidify>, TypedMultipart<ParametersValidifyWithoutPayload>,
>, >,
) -> StatusCode { ) -> StatusCode {
check_validified(&parameters) check_validified(&parameters)
@@ -1401,7 +1443,7 @@ mod typed_multipart {
pub(super) async fn extract_base_multipart( pub(super) async fn extract_base_multipart(
Validated(BaseMultipart { data, .. }): Validated< Validated(BaseMultipart { data, .. }): Validated<
BaseMultipart<ParametersValidify, TypedMultipartError>, BaseMultipart<ParametersValidifyWithoutPayload, TypedMultipartError>,
>, >,
) -> StatusCode { ) -> StatusCode {
check_validated(&data) check_validated(&data)
@@ -1409,7 +1451,7 @@ mod typed_multipart {
pub(super) async fn extract_base_multipart_modified( pub(super) async fn extract_base_multipart_modified(
Modified(BaseMultipart { data, .. }): Modified< Modified(BaseMultipart { data, .. }): Modified<
BaseMultipart<ParametersValidify, TypedMultipartError>, BaseMultipart<ParametersValidifyWithoutPayload, TypedMultipartError>,
>, >,
) -> StatusCode { ) -> StatusCode {
check_modified(&data) check_modified(&data)
@@ -1417,7 +1459,7 @@ mod typed_multipart {
pub(super) async fn extract_base_multipart_validified_by_ref( pub(super) async fn extract_base_multipart_validified_by_ref(
ValidifiedByRef(BaseMultipart { data, .. }): ValidifiedByRef< ValidifiedByRef(BaseMultipart { data, .. }): ValidifiedByRef<
BaseMultipart<ParametersValidify, TypedMultipartError>, BaseMultipart<ParametersValidifyWithoutPayload, TypedMultipartError>,
>, >,
) -> StatusCode { ) -> StatusCode {
check_validified(&data) check_validified(&data)
@@ -1813,7 +1855,9 @@ mod extra_form {
#[cfg(feature = "extra_protobuf")] #[cfg(feature = "extra_protobuf")]
mod extra_protobuf { mod extra_protobuf {
use super::{check_modified, check_validated, check_validified, ParametersValidify}; use super::{
check_modified, check_validated, check_validified, ParametersValidifyWithoutPayload,
};
use crate::{Modified, Validated, ValidifiedByRef}; use crate::{Modified, Validated, ValidifiedByRef};
use axum::http::StatusCode; use axum::http::StatusCode;
use axum_extra::protobuf::Protobuf; use axum_extra::protobuf::Protobuf;
@@ -1825,19 +1869,21 @@ mod extra_protobuf {
} }
pub async fn extract_extra_protobuf( pub async fn extract_extra_protobuf(
Validated(Protobuf(parameters)): Validated<Protobuf<ParametersValidify>>, Validated(Protobuf(parameters)): Validated<Protobuf<ParametersValidifyWithoutPayload>>,
) -> StatusCode { ) -> StatusCode {
check_validated(&parameters) check_validated(&parameters)
} }
pub async fn extract_extra_protobuf_modified( pub async fn extract_extra_protobuf_modified(
Modified(Protobuf(parameters)): Modified<Protobuf<ParametersValidify>>, Modified(Protobuf(parameters)): Modified<Protobuf<ParametersValidifyWithoutPayload>>,
) -> StatusCode { ) -> StatusCode {
check_modified(&parameters) check_modified(&parameters)
} }
pub async fn extract_extra_protobuf_validified_by_ref( pub async fn extract_extra_protobuf_validified_by_ref(
ValidifiedByRef(Protobuf(parameters)): ValidifiedByRef<Protobuf<ParametersValidify>>, ValidifiedByRef(Protobuf(parameters)): ValidifiedByRef<
Protobuf<ParametersValidifyWithoutPayload>,
>,
) -> StatusCode { ) -> StatusCode {
check_validified(&parameters) check_validified(&parameters)
} }

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Xml<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for Xml<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for Xml<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = Xml<T::Payload>; type PayloadExtractor = Xml<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
Xml(v) Xml(v)
} }
} }

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Yaml<T> {
} }
#[cfg(feature = "validify")] #[cfg(feature = "validify")]
impl<T: validify::Validify> crate::HasValidify for Yaml<T> { impl<T: validify::Validify + validify::ValidifyPayload> crate::HasValidify for Yaml<T> {
type Validify = T; type Validify = T;
type PayloadExtractor = Yaml<T::Payload>; type PayloadExtractor = Yaml<T::Payload>;
fn from_validified(v: Self::Validify) -> Self { fn from_validify(v: Self::Validify) -> Self {
Yaml(v) Yaml(v)
} }
} }