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 }
garde = { version = "0.16.3", optional = true }
validator = { version = "0.16.1", optional = true}
validify = { version = "=1.0", optional = true }
validify_derive = { version = "=1.0", optional = true }
validify = { version = "1.3.0", optional = true}
[dependencies.axum-extra]
version = "0.9.0"
@@ -74,7 +73,7 @@ default = ["basic", "validator"]
basic = ["json", "form", "query"]
garde = ["dep:garde"]
validator = ["dep:validator"]
validify = ["dep:validify", "dep:validify_derive"]
validify = ["dep:validify"]
json = ["axum/json"]
form = ["axum/form"]
query = ["axum/query"]

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Form<T> {
}
#[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 PayloadExtractor = Form<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
Form(v)
}
}

View File

@@ -126,11 +126,11 @@ impl<T> crate::PayloadExtractor for Query<T> {
}
#[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 PayloadExtractor = Query<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
Query(v)
}
}

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Form<T> {
}
#[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 PayloadExtractor = Form<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
Form(v)
}
}

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Json<T> {
}
#[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 PayloadExtractor = Json<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
Json(v)
}
}

View File

@@ -133,10 +133,10 @@ impl<T> crate::PayloadExtractor for MsgPack<T> {
}
#[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 PayloadExtractor = MsgPack<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
MsgPack(v)
}
}
@@ -175,10 +175,10 @@ impl<T> crate::PayloadExtractor for MsgPackRaw<T> {
}
#[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 PayloadExtractor = MsgPackRaw<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
MsgPackRaw(v)
}
}

View File

@@ -122,11 +122,11 @@ impl<T> crate::PayloadExtractor for Path<T> {
}
#[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 PayloadExtractor = Path<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
Path(v)
}
}

View File

@@ -126,11 +126,11 @@ impl<T> crate::PayloadExtractor for Query<T> {
}
#[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 PayloadExtractor = Query<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
Query(v)
}
}

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Toml<T> {
}
#[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 PayloadExtractor = Toml<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
Toml(v)
}
}

View File

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

View File

@@ -18,15 +18,24 @@ use std::any::type_name;
use std::net::SocketAddr;
use std::ops::Deref;
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 = "typed_multipart",
derive(axum_typed_multipart::TryFromMultipart)
)]
pub struct ParametersValidify {
pub struct ParametersValidifyWithoutPayload {
#[validate(range(min = 5.0, max = 10.0))]
#[cfg_attr(feature = "extra_protobuf", prost(int32, tag = "1"))]
v0: i32,
@@ -56,6 +65,18 @@ static INVALID_PARAMETERS: Lazy<ParametersValidify> = Lazy::new(|| ParametersVal
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 {
fn valid() -> &'static Self {
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 {
type Validate = ParametersValidify;
@@ -836,21 +871,21 @@ async fn test_main() -> anyhow::Result<()> {
use axum_extra::protobuf::Protobuf;
// Validated
test_executor
.execute::<Protobuf<ParametersValidify>>(
.execute::<Protobuf<ParametersValidifyWithoutPayload>>(
Method::POST,
extra_protobuf::route::EXTRA_PROTOBUF,
)
.await?;
// Modified
test_executor
.execute_modified::<Protobuf<ParametersValidify>>(
.execute_modified::<Protobuf<ParametersValidifyWithoutPayload>>(
Method::POST,
extra_protobuf::route::EXTRA_PROTOBUF_MODIFIED,
)
.await?;
// ValidifiedByRef
test_executor
.execute::<Protobuf<ParametersValidify>>(
.execute::<Protobuf<ParametersValidifyWithoutPayload>>(
Method::POST,
extra_protobuf::route::EXTRA_PROTOBUF_VALIDIFIED_BY_REF,
)
@@ -1356,7 +1391,10 @@ mod typed_header {
#[cfg(feature = "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 axum::http::StatusCode;
use axum_typed_multipart::{BaseMultipart, TypedMultipart, TypedMultipartError};
@@ -1380,20 +1418,24 @@ mod typed_multipart {
}
pub(super) async fn extract_typed_multipart(
Validated(TypedMultipart(parameters)): Validated<TypedMultipart<ParametersValidify>>,
Validated(TypedMultipart(parameters)): Validated<
TypedMultipart<ParametersValidifyWithoutPayload>,
>,
) -> StatusCode {
check_validated(&parameters)
}
pub(super) async fn extract_typed_multipart_modified(
Modified(TypedMultipart(parameters)): Modified<TypedMultipart<ParametersValidify>>,
Modified(TypedMultipart(parameters)): Modified<
TypedMultipart<ParametersValidifyWithoutPayload>,
>,
) -> StatusCode {
check_modified(&parameters)
}
pub(super) async fn extract_typed_multipart_validified_by_ref(
ValidifiedByRef(TypedMultipart(parameters)): ValidifiedByRef<
TypedMultipart<ParametersValidify>,
TypedMultipart<ParametersValidifyWithoutPayload>,
>,
) -> StatusCode {
check_validified(&parameters)
@@ -1401,7 +1443,7 @@ mod typed_multipart {
pub(super) async fn extract_base_multipart(
Validated(BaseMultipart { data, .. }): Validated<
BaseMultipart<ParametersValidify, TypedMultipartError>,
BaseMultipart<ParametersValidifyWithoutPayload, TypedMultipartError>,
>,
) -> StatusCode {
check_validated(&data)
@@ -1409,7 +1451,7 @@ mod typed_multipart {
pub(super) async fn extract_base_multipart_modified(
Modified(BaseMultipart { data, .. }): Modified<
BaseMultipart<ParametersValidify, TypedMultipartError>,
BaseMultipart<ParametersValidifyWithoutPayload, TypedMultipartError>,
>,
) -> StatusCode {
check_modified(&data)
@@ -1417,7 +1459,7 @@ mod typed_multipart {
pub(super) async fn extract_base_multipart_validified_by_ref(
ValidifiedByRef(BaseMultipart { data, .. }): ValidifiedByRef<
BaseMultipart<ParametersValidify, TypedMultipartError>,
BaseMultipart<ParametersValidifyWithoutPayload, TypedMultipartError>,
>,
) -> StatusCode {
check_validified(&data)
@@ -1813,7 +1855,9 @@ mod extra_form {
#[cfg(feature = "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 axum::http::StatusCode;
use axum_extra::protobuf::Protobuf;
@@ -1825,19 +1869,21 @@ mod extra_protobuf {
}
pub async fn extract_extra_protobuf(
Validated(Protobuf(parameters)): Validated<Protobuf<ParametersValidify>>,
Validated(Protobuf(parameters)): Validated<Protobuf<ParametersValidifyWithoutPayload>>,
) -> StatusCode {
check_validated(&parameters)
}
pub async fn extract_extra_protobuf_modified(
Modified(Protobuf(parameters)): Modified<Protobuf<ParametersValidify>>,
Modified(Protobuf(parameters)): Modified<Protobuf<ParametersValidifyWithoutPayload>>,
) -> StatusCode {
check_modified(&parameters)
}
pub async fn extract_extra_protobuf_validified_by_ref(
ValidifiedByRef(Protobuf(parameters)): ValidifiedByRef<Protobuf<ParametersValidify>>,
ValidifiedByRef(Protobuf(parameters)): ValidifiedByRef<
Protobuf<ParametersValidifyWithoutPayload>,
>,
) -> StatusCode {
check_validified(&parameters)
}

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Xml<T> {
}
#[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 PayloadExtractor = Xml<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
Xml(v)
}
}

View File

@@ -126,10 +126,10 @@ impl<T> crate::PayloadExtractor for Yaml<T> {
}
#[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 PayloadExtractor = Yaml<T::Payload>;
fn from_validified(v: Self::Validify) -> Self {
fn from_validify(v: Self::Validify) -> Self {
Yaml(v)
}
}