add tests for WithRejection and Cached; update README.md

This commit is contained in:
gengteng
2023-09-29 15:55:20 +08:00
parent 3d055d11a3
commit 1270a3654d
2 changed files with 72 additions and 6 deletions

View File

@@ -7,11 +7,11 @@
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/gengteng/axum-valid/.github/workflows/main.yml?branch=main)](https://github.com/gengteng/axum-valid/actions/workflows/ci.yml) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/gengteng/axum-valid/.github/workflows/main.yml?branch=main)](https://github.com/gengteng/axum-valid/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/gengteng/axum-valid/badge.svg?branch=main)](https://coveralls.io/github/gengteng/axum-valid?branch=main) [![Coverage Status](https://coveralls.io/repos/github/gengteng/axum-valid/badge.svg?branch=main)](https://coveralls.io/github/gengteng/axum-valid?branch=main)
This crate provides a `Valid` type that can be used in combination with `Json`, `Path`, `Query`, and `Form` extractors to validate the entities that implement the `Validate` trait from the `validator` crate. This crate provides a `Valid` type for use with `Json`, `Path`, `Query`, and `Form` extractors to validate entities implementing the `Validate` trait from the `validator` crate.
It also provides a `ValidEx` type that works similarly to `Valid`, but can perform validation requiring additional arguments by using types that implement the `ValidateArgs` trait. A `ValidEx` type is also available. Similar to `Valid`, `ValidEx` can execute validations requiring extra arguments with types that implement the `ValidateArgs` trait from the `validator` crate.
Additional extractors like `TypedHeader`, `MsgPack`, `Yaml` etc. are supported through optional features. The full list of supported extractors is in the Features section below. Additional extractors such as `TypedHeader`, `MsgPack`, `Yaml`, and others are supported through optional features. The complete list of supported extractors can be found in the Features section below.
## Basic usage ## Basic usage

View File

@@ -1,5 +1,5 @@
use crate::tests::{ValidTest, ValidTestParameter}; use crate::tests::{ValidTest, ValidTestParameter};
use crate::{Arguments, HasValidate, Valid, ValidEx, VALIDATION_ERROR_STATUS}; use crate::{Arguments, HasValidate, HasValidateArgs, Valid, ValidEx, VALIDATION_ERROR_STATUS};
use axum::extract::{FromRef, Path, Query}; use axum::extract::{FromRef, Path, Query};
use axum::routing::{get, post}; use axum::routing::{get, post};
use axum::{Form, Json, Router}; use axum::{Form, Json, Router};
@@ -114,6 +114,14 @@ impl HasValidate for Parameters {
} }
} }
impl<'v> HasValidateArgs<'v> for ParametersEx {
type ValidateArgs = ParametersEx;
fn get_validate_args(&self) -> &Self::ValidateArgs {
self
}
}
#[derive(Debug, Clone, FromRef)] #[derive(Debug, Clone, FromRef)]
struct MyState { struct MyState {
param_validation_ctx: ParametersExValidationArguments, param_validation_ctx: ParametersExValidationArguments,
@@ -172,13 +180,22 @@ async fn test_main() -> anyhow::Result<()> {
#[cfg(feature = "extra")] #[cfg(feature = "extra")]
let router = router let router = router
.route(extra::route::CACHED, post(extra::extract_cached)) .route(extra::route::CACHED, post(extra::extract_cached))
.route(extra::route::CACHED_EX, post(extra::extract_cached_ex))
.route( .route(
extra::route::WITH_REJECTION, extra::route::WITH_REJECTION,
post(extra::extract_with_rejection), post(extra::extract_with_rejection),
) )
.route(
extra::route::WITH_REJECTION_EX,
post(extra::extract_with_rejection_ex),
)
.route( .route(
extra::route::WITH_REJECTION_VALID, extra::route::WITH_REJECTION_VALID,
post(extra::extract_with_rejection_valid), post(extra::extract_with_rejection_valid),
)
.route(
extra::route::WITH_REJECTION_VALID_EX,
post(extra::extract_with_rejection_valid_ex),
); );
#[cfg(feature = "extra_typed_path")] #[cfg(feature = "extra_typed_path")]
@@ -875,9 +892,12 @@ mod typed_multipart {
#[cfg(feature = "extra")] #[cfg(feature = "extra")]
mod extra { mod extra {
use crate::test::{validate_again, Parameters}; use crate::test::{
validate_again, validate_again_ex, Parameters, ParametersEx,
ParametersExValidationArguments,
};
use crate::tests::{Rejection, ValidTest, ValidTestParameter}; use crate::tests::{Rejection, ValidTest, ValidTestParameter};
use crate::{Valid, ValidRejection}; use crate::{Arguments, Valid, ValidEx, ValidRejection};
use axum::extract::FromRequestParts; use axum::extract::FromRequestParts;
use axum::http::request::Parts; use axum::http::request::Parts;
use axum::http::StatusCode; use axum::http::StatusCode;
@@ -887,8 +907,11 @@ mod extra {
pub mod route { pub mod route {
pub const CACHED: &str = "/cached"; pub const CACHED: &str = "/cached";
pub const CACHED_EX: &str = "/cached_ex";
pub const WITH_REJECTION: &str = "/with_rejection"; pub const WITH_REJECTION: &str = "/with_rejection";
pub const WITH_REJECTION_EX: &str = "/with_rejection_ex";
pub const WITH_REJECTION_VALID: &str = "/with_rejection_valid"; pub const WITH_REJECTION_VALID: &str = "/with_rejection_valid";
pub const WITH_REJECTION_VALID_EX: &str = "/with_rejection_valid_ex";
} }
pub const PARAMETERS_HEADER: &str = "parameters-header"; pub const PARAMETERS_HEADER: &str = "parameters-header";
pub const CACHED_REJECTION_STATUS: StatusCode = StatusCode::FORBIDDEN; pub const CACHED_REJECTION_STATUS: StatusCode = StatusCode::FORBIDDEN;
@@ -931,6 +954,22 @@ mod extra {
} }
} }
#[axum::async_trait]
impl<S> FromRequestParts<S> for ParametersEx
where
S: Send + Sync,
{
type Rejection = ParametersRejection;
async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
let Some(value) = parts.headers.get(PARAMETERS_HEADER) else {
return Err(ParametersRejection::Null);
};
serde_json::from_slice(value.as_bytes()).map_err(ParametersRejection::InvalidJson)
}
}
impl ValidTest for Parameters { impl ValidTest for Parameters {
const ERROR_STATUS_CODE: StatusCode = CACHED_REJECTION_STATUS; const ERROR_STATUS_CODE: StatusCode = CACHED_REJECTION_STATUS;
@@ -987,6 +1026,15 @@ mod extra {
validate_again(parameters) validate_again(parameters)
} }
pub async fn extract_cached_ex(
ValidEx(Cached(parameters), args): ValidEx<
Cached<ParametersEx>,
ParametersExValidationArguments,
>,
) -> StatusCode {
validate_again_ex(parameters, args.get())
}
pub async fn extract_with_rejection( pub async fn extract_with_rejection(
Valid(WithRejection(parameters, _)): Valid< Valid(WithRejection(parameters, _)): Valid<
WithRejection<Parameters, ValidWithRejectionRejection>, WithRejection<Parameters, ValidWithRejectionRejection>,
@@ -995,6 +1043,15 @@ mod extra {
validate_again(parameters) validate_again(parameters)
} }
pub async fn extract_with_rejection_ex(
ValidEx(WithRejection(parameters, _), args): ValidEx<
WithRejection<ParametersEx, ValidWithRejectionRejection>,
ParametersExValidationArguments,
>,
) -> StatusCode {
validate_again_ex(parameters, args.get())
}
pub struct WithRejectionValidRejection<E> { pub struct WithRejectionValidRejection<E> {
inner: ValidRejection<E>, inner: ValidRejection<E>,
} }
@@ -1021,6 +1078,15 @@ mod extra {
) -> StatusCode { ) -> StatusCode {
validate_again(parameters) validate_again(parameters)
} }
pub async fn extract_with_rejection_valid_ex(
WithRejection(ValidEx(parameters, args), _): WithRejection<
ValidEx<ParametersEx, ParametersExValidationArguments>,
WithRejectionValidRejection<ParametersRejection>,
>,
) -> StatusCode {
validate_again_ex(parameters, args.get())
}
} }
#[cfg(feature = "extra_typed_path")] #[cfg(feature = "extra_typed_path")]