feat: Update validator to v0.17.0 and refactor argument-based validation using validator
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "axum-valid"
|
name = "axum-valid"
|
||||||
version = "0.16.0"
|
version = "0.17.0"
|
||||||
description = "Provides validation extractors for your Axum application, allowing you to validate data using validator, garde, validify or all of them."
|
description = "Provides validation extractors for your Axum application, allowing you to validate data using validator, garde, validify or all of them."
|
||||||
authors = ["GengTeng <me@gteng.org>"]
|
authors = ["GengTeng <me@gteng.org>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -27,7 +27,7 @@ features = ["full", "aide"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { version = "0.7.3", default-features = false }
|
axum = { version = "0.7.3", default-features = false }
|
||||||
garde = { version = "0.18.0", optional = true }
|
garde = { version = "0.18.0", optional = true }
|
||||||
validator = { version = "0.16.1", optional = true }
|
validator = { version = "0.17.0", optional = true }
|
||||||
validify = { version = "1.3.0", optional = true }
|
validify = { version = "1.3.0", optional = true }
|
||||||
|
|
||||||
[dependencies.axum-extra]
|
[dependencies.axum-extra]
|
||||||
@@ -57,7 +57,7 @@ axum = { version = "0.7.1", features = ["macros"] }
|
|||||||
tokio = { version = "1.34.0", features = ["full"] }
|
tokio = { version = "1.34.0", features = ["full"] }
|
||||||
reqwest = { version = "0.11.23", features = ["json", "multipart"] }
|
reqwest = { version = "0.11.23", features = ["json", "multipart"] }
|
||||||
serde = { version = "1.0.195", features = ["derive"] }
|
serde = { version = "1.0.195", features = ["derive"] }
|
||||||
validator = { version = "0.16.1", features = ["derive"] }
|
validator = { version = "0.17.0", features = ["derive"] }
|
||||||
garde = { version = "0.18.0", features = ["serde", "derive"] }
|
garde = { version = "0.18.0", features = ["serde", "derive"] }
|
||||||
serde_json = "1.0.108"
|
serde_json = "1.0.108"
|
||||||
serde_yaml = "0.9.27"
|
serde_yaml = "0.9.27"
|
||||||
|
|||||||
58
README.md
58
README.md
@@ -9,7 +9,9 @@
|
|||||||
|
|
||||||
## 📑 Overview
|
## 📑 Overview
|
||||||
|
|
||||||
**axum-valid** is a library that provides data validation extractors for the Axum web framework. It integrates **validator**, **garde** and **validify**, three popular validation crates in the Rust ecosystem, to offer convenient validation and data handling extractors for Axum applications.
|
**axum-valid** is a library that provides data validation extractors for the Axum web framework. It integrates *
|
||||||
|
*validator**, **garde** and **validify**, three popular validation crates in the Rust ecosystem, to offer convenient
|
||||||
|
validation and data handling extractors for Axum applications.
|
||||||
|
|
||||||
## 🚀 Basic usage
|
## 🚀 Basic usage
|
||||||
|
|
||||||
@@ -66,7 +68,8 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In case of inner extractor errors, it will first return the Rejection from the inner extractor. When validation errors occur, the outer extractor will automatically return 400 with validation errors as the HTTP message body.
|
In case of inner extractor errors, it will first return the Rejection from the inner extractor. When validation errors
|
||||||
|
occur, the outer extractor will automatically return 400 with validation errors as the HTTP message body.
|
||||||
|
|
||||||
### 📦 `Garde<E>`
|
### 📦 `Garde<E>`
|
||||||
|
|
||||||
@@ -239,11 +242,12 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To see how each inner extractor can be used with validation extractors, please refer to the example in the [documentation](https://docs.rs/axum-valid) of the corresponding module.
|
To see how each inner extractor can be used with validation extractors, please refer to the example in
|
||||||
|
the [documentation](https://docs.rs/axum-valid) of the corresponding module.
|
||||||
|
|
||||||
## 🚀 Argument-Based Validation
|
## 🚀 Argument-Based Validation
|
||||||
|
|
||||||
### 📦 `ValidEx<E, A>`
|
### 📦 `ValidEx<E>`
|
||||||
|
|
||||||
* Install
|
* Install
|
||||||
|
|
||||||
@@ -258,35 +262,34 @@ cargo add axum-valid
|
|||||||
```rust,ignore
|
```rust,ignore
|
||||||
use axum::routing::post;
|
use axum::routing::post;
|
||||||
use axum::{Form, Router};
|
use axum::{Form, Router};
|
||||||
use axum_valid::{Arguments, ValidEx};
|
use axum_valid::ValidEx;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::ops::{RangeFrom, RangeInclusive};
|
use std::ops::{RangeFrom, RangeInclusive};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use validator::{Validate, ValidateArgs, ValidationError};
|
use validator::{Validate, ValidationError};
|
||||||
|
|
||||||
// NOTE: When some fields use custom validation functions with arguments,
|
// NOTE: When some fields use custom validation functions with arguments,
|
||||||
// `#[derive(Validate)]` will implement `ValidateArgs` instead of `Validate` for the type.
|
// `#[derive(Validate)]` will implement `ValidateArgs` instead of `Validate` for the type.
|
||||||
// The validation arguments will be a tuple of all the field validation args.
|
|
||||||
// In this example it is (&RangeInclusive<usize>, &RangeFrom<usize>).
|
|
||||||
// For more detailed information and understanding of `ValidateArgs` and their argument types,
|
|
||||||
// please refer to the `validator` crate documentation.
|
|
||||||
#[derive(Debug, Validate, Deserialize)]
|
#[derive(Debug, Validate, Deserialize)]
|
||||||
|
#[validate(context = PagerValidArgs)] // context is required
|
||||||
pub struct Pager {
|
pub struct Pager {
|
||||||
#[validate(custom(function = "validate_page_size", arg = "&'v_a RangeInclusive<usize>"))]
|
#[validate(custom(function = "validate_page_size", use_context))]
|
||||||
pub page_size: usize,
|
pub page_size: usize,
|
||||||
#[validate(custom(function = "validate_page_no", arg = "&'v_a RangeFrom<usize>"))]
|
#[validate(custom(function = "validate_page_no", use_context))]
|
||||||
pub page_no: usize,
|
pub page_no: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_page_size(v: usize, args: &RangeInclusive<usize>) -> Result<(), ValidationError> {
|
fn validate_page_size(v: &usize, args: &PagerValidArgs) -> Result<(), ValidationError> {
|
||||||
args.contains(&v)
|
args.page_size_range
|
||||||
|
.contains(&v)
|
||||||
.then_some(())
|
.then_some(())
|
||||||
.ok_or_else(|| ValidationError::new("page_size is out of range"))
|
.ok_or_else(|| ValidationError::new("page_size is out of range"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_page_no(v: usize, args: &RangeFrom<usize>) -> Result<(), ValidationError> {
|
fn validate_page_no(v: &usize, args: &PagerValidArgs) -> Result<(), ValidationError> {
|
||||||
args.contains(&v)
|
args.page_no_range
|
||||||
|
.contains(&v)
|
||||||
.then_some(())
|
.then_some(())
|
||||||
.ok_or_else(|| ValidationError::new("page_no is out of range"))
|
.ok_or_else(|| ValidationError::new("page_no is out of range"))
|
||||||
}
|
}
|
||||||
@@ -298,18 +301,7 @@ pub struct PagerValidArgs {
|
|||||||
page_no_range: RangeFrom<usize>,
|
page_no_range: RangeFrom<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This implementation allows PagerValidArgs to be the second member of ValidEx, and provides arguments for actual validation.
|
pub async fn pager_from_form_ex(ValidEx(Form(pager)): ValidEx<Form<Pager>>) {
|
||||||
// get() method returns the actual validation arguments to be used during validation.
|
|
||||||
impl<'a> Arguments<'a> for PagerValidArgs {
|
|
||||||
type T = Pager;
|
|
||||||
|
|
||||||
// NOTE: <Pager as ValidateArgs<'a>>::Args == (&RangeInclusive<usize>, &RangeFrom<usize>)
|
|
||||||
fn get(&'a self) -> <Pager as ValidateArgs<'a>>::Args {
|
|
||||||
(&self.page_size_range, &self.page_no_range)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn pager_from_form_ex(ValidEx(Form(pager), _): ValidEx<Form<Pager>, PagerValidArgs>) {
|
|
||||||
assert!((1..=50).contains(&pager.page_size));
|
assert!((1..=50).contains(&pager.page_size));
|
||||||
assert!((1..).contains(&pager.page_no));
|
assert!((1..).contains(&pager.page_no));
|
||||||
}
|
}
|
||||||
@@ -408,11 +400,10 @@ Current module documentation predominantly showcases `Valid` examples, the usage
|
|||||||
|
|
||||||
## 🗂️ Extractors List
|
## 🗂️ Extractors List
|
||||||
|
|
||||||
|
|
||||||
| Extractor | Backend / Feature | Data's trait bound | Functionality | Benefits | Drawbacks |
|
| Extractor | Backend / Feature | Data's trait bound | Functionality | Benefits | Drawbacks |
|
||||||
|-----------------------|-------------------|---------------------------------------------------------------------------------|----------------------------------------|--------------------------------------------|--------------------------------------------------|
|
|-----------------------|-------------------|---------------------------------------------------------------------------------|----------------------------------------|--------------------------------------------|--------------------------------------------------|
|
||||||
| `Valid<E>` | validator | `validator::Validate` | Validation | | |
|
| `Valid<E>` | validator | `validator::Validate` | Validation | | |
|
||||||
| `ValidEx<E, A>` | validator | `validator::ValidateArgs` | Validation with arguments | | More complex arguments coding |
|
| `ValidEx<E>` | validator | `validator::ValidateArgs` | Validation with arguments | | |
|
||||||
| `Garde<E>` | garde | `garde::Validate` | Validation with or without arguments | | Require empty tuple as the argument if use state | |
|
| `Garde<E>` | garde | `garde::Validate` | Validation with or without arguments | | Require empty tuple as the argument if use state | |
|
||||||
| `Validated<E>` | validify | `validify::Validate` | Validation | | |
|
| `Validated<E>` | validify | `validify::Validate` | Validation | | |
|
||||||
| `Modified<E>` | validify | `validify::Modify` | Modification / Conversion to response | | |
|
| `Modified<E>` | validify | `validify::Modify` | Modification / Conversion to response | | |
|
||||||
@@ -437,6 +428,7 @@ Current module documentation predominantly showcases `Valid` examples, the usage
|
|||||||
| yaml | Enables support for `Yaml` from `axum-serde` | [`yaml`] | ❌ | ✅ | ✅ |
|
| yaml | Enables support for `Yaml` from `axum-serde` | [`yaml`] | ❌ | ✅ | ✅ |
|
||||||
| xml | Enables support for `Xml` from `axum-serde` | [`xml`] | ❌ | ✅ | ✅ |
|
| xml | Enables support for `Xml` from `axum-serde` | [`xml`] | ❌ | ✅ | ✅ |
|
||||||
| toml | Enables support for `Toml` from `axum-serde` | [`toml`] | ❌ | ✅ | ✅ |
|
| toml | Enables support for `Toml` from `axum-serde` | [`toml`] | ❌ | ✅ | ✅ |
|
||||||
|
| sonic | Enables support for `Sonic` from `axum-serde` | [`sonic`] | ❌ | ✅ | ✅ |
|
||||||
| extra | Enables support for `Cached`, `WithRejection` from `axum-extra` | [`extra`] | ❌ | ✅ | ✅ |
|
| extra | Enables support for `Cached`, `WithRejection` from `axum-extra` | [`extra`] | ❌ | ✅ | ✅ |
|
||||||
| extra_typed_path | Enables support for `T: TypedPath` from `axum-extra` | [`extra::typed_path`] | ❌ | ✅ | ✅ |
|
| extra_typed_path | Enables support for `T: TypedPath` from `axum-extra` | [`extra::typed_path`] | ❌ | ✅ | ✅ |
|
||||||
| extra_query | Enables support for `Query` from `axum-extra` | [`extra::query`] | ❌ | ✅ | ✅ |
|
| extra_query | Enables support for `Query` from `axum-extra` | [`extra::query`] | ❌ | ✅ | ✅ |
|
||||||
@@ -454,9 +446,11 @@ Current module documentation predominantly showcases `Valid` examples, the usage
|
|||||||
|
|
||||||
## 🔌 Compatibility
|
## 🔌 Compatibility
|
||||||
|
|
||||||
To determine the compatible versions of dependencies that work together, please refer to the dependencies listed in the `Cargo.toml` file. The version numbers listed there will indicate the compatible versions.
|
To determine the compatible versions of dependencies that work together, please refer to the dependencies listed in
|
||||||
|
the `Cargo.toml` file. The version numbers listed there will indicate the compatible versions.
|
||||||
|
|
||||||
If you encounter code compilation problems, it could be attributed to either **missing trait bounds**, **unmet feature requirements**, or **incorrect dependency version selections**.
|
If you encounter code compilation problems, it could be attributed to either **missing trait bounds**, **unmet feature
|
||||||
|
requirements**, or **incorrect dependency version selections**.
|
||||||
|
|
||||||
## 📜 License
|
## 📜 License
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ impl<T: TypedPath + Display> TypedPath for Valid<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "validator")]
|
#[cfg(feature = "validator")]
|
||||||
impl<T: TypedPath + Display, A> TypedPath for ValidEx<T, A> {
|
impl<T: TypedPath + Display> TypedPath for ValidEx<T> {
|
||||||
const PATH: &'static str = T::PATH;
|
const PATH: &'static str = T::PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ pub trait HasValidate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "validator")]
|
#[cfg(feature = "validator")]
|
||||||
pub use crate::validator::{Arguments, HasValidateArgs, Valid, ValidEx, ValidRejection};
|
pub use crate::validator::{HasValidateArgs, Valid, ValidEx, ValidRejection};
|
||||||
|
|
||||||
#[cfg(feature = "garde")]
|
#[cfg(feature = "garde")]
|
||||||
pub use crate::garde::{Garde, GardeRejection};
|
pub use crate::garde::{Garde, GardeRejection};
|
||||||
|
|||||||
@@ -81,9 +81,9 @@ where
|
|||||||
/// Although current module documentation predominantly showcases `Valid` examples, the usage of `ValidEx` is analogous.
|
/// Although current module documentation predominantly showcases `Valid` examples, the usage of `ValidEx` is analogous.
|
||||||
///
|
///
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct ValidEx<E, A>(pub E, pub A);
|
pub struct ValidEx<E>(pub E);
|
||||||
|
|
||||||
impl<E, A> Deref for ValidEx<E, A> {
|
impl<E> Deref for ValidEx<E> {
|
||||||
type Target = E;
|
type Target = E;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@@ -91,19 +91,19 @@ impl<E, A> Deref for ValidEx<E, A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, A> DerefMut for ValidEx<E, A> {
|
impl<E> DerefMut for ValidEx<E> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Display, A> Display for ValidEx<T, A> {
|
impl<T: Display> Display for ValidEx<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.fmt(f)
|
self.0.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, A> ValidEx<E, A> {
|
impl<E> ValidEx<E> {
|
||||||
/// Consumes the `ValidEx` and returns the validated data within.
|
/// Consumes the `ValidEx` and returns the validated data within.
|
||||||
///
|
///
|
||||||
/// This returns the `E` type which represents the data that has been
|
/// This returns the `E` type which represents the data that has been
|
||||||
@@ -111,22 +111,10 @@ impl<E, A> ValidEx<E, A> {
|
|||||||
pub fn into_inner(self) -> E {
|
pub fn into_inner(self) -> E {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the validation arguments.
|
|
||||||
///
|
|
||||||
/// This provides access to the `A` type which contains the arguments used
|
|
||||||
/// to validate the data. These arguments were passed to the validation
|
|
||||||
/// function.
|
|
||||||
pub fn arguments<'a>(&'a self) -> <<A as Arguments<'a>>::T as ValidateArgs<'a>>::Args
|
|
||||||
where
|
|
||||||
A: Arguments<'a>,
|
|
||||||
{
|
|
||||||
self.1.get()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "aide")]
|
#[cfg(feature = "aide")]
|
||||||
impl<T, A> aide::OperationInput for ValidEx<T, A>
|
impl<T> aide::OperationInput for ValidEx<T>
|
||||||
where
|
where
|
||||||
T: aide::OperationInput,
|
T: aide::OperationInput,
|
||||||
{
|
{
|
||||||
@@ -135,23 +123,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Arguments` provides the validation arguments for the data type `T`.
|
|
||||||
///
|
|
||||||
/// This trait has an associated type `T` which represents the data type to
|
|
||||||
/// validate. `T` must implement the `ValidateArgs` trait which defines the
|
|
||||||
/// validation logic.
|
|
||||||
///
|
|
||||||
/// It's important to mention that types implementing `Arguments` should be a part of the router's state
|
|
||||||
/// (either through implementing `FromRef<StateType>` or by directly becoming the state)
|
|
||||||
/// to enable automatic arguments retrieval during validation.
|
|
||||||
///
|
|
||||||
pub trait Arguments<'a> {
|
|
||||||
/// The data type to validate using this arguments
|
|
||||||
type T: ValidateArgs<'a>;
|
|
||||||
/// This method gets the arguments required by `ValidateArgs::validate_args`
|
|
||||||
fn get(&'a self) -> <<Self as Arguments<'a>>::T as ValidateArgs<'a>>::Args;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `ValidRejection` is returned when the `Valid` or `ValidEx` extractor fails.
|
/// `ValidRejection` is returned when the `Valid` or `ValidEx` extractor fails.
|
||||||
///
|
///
|
||||||
pub type ValidRejection<E> = ValidationRejection<ValidationErrors, E>;
|
pub type ValidRejection<E> = ValidationRejection<ValidationErrors, E>;
|
||||||
@@ -210,14 +181,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<State, Extractor, Args> FromRequest<State> for ValidEx<Extractor, Args>
|
impl<State, Extractor, Args> FromRequest<State> for ValidEx<Extractor>
|
||||||
where
|
where
|
||||||
State: Send + Sync,
|
State: Send + Sync,
|
||||||
Args: Send
|
Args: Send + Sync + FromRef<State>,
|
||||||
+ Sync
|
|
||||||
+ FromRef<State>
|
|
||||||
+ for<'a> Arguments<'a, T = <Extractor as HasValidateArgs<'a>>::ValidateArgs>,
|
|
||||||
Extractor: for<'v> HasValidateArgs<'v> + FromRequest<State>,
|
Extractor: for<'v> HasValidateArgs<'v> + FromRequest<State>,
|
||||||
|
for<'v> <Extractor as HasValidateArgs<'v>>::ValidateArgs: ValidateArgs<'v, Args = &'v Args>,
|
||||||
{
|
{
|
||||||
type Rejection = ValidRejection<<Extractor as FromRequest<State>>::Rejection>;
|
type Rejection = ValidRejection<<Extractor as FromRequest<State>>::Rejection>;
|
||||||
|
|
||||||
@@ -227,20 +196,18 @@ where
|
|||||||
.await
|
.await
|
||||||
.map_err(ValidRejection::Inner)?;
|
.map_err(ValidRejection::Inner)?;
|
||||||
|
|
||||||
inner.get_validate_args().validate_args(arguments.get())?;
|
inner.get_validate_args().validate_with_args(&arguments)?;
|
||||||
Ok(ValidEx(inner, arguments))
|
Ok(ValidEx(inner))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<State, Extractor, Args> FromRequestParts<State> for ValidEx<Extractor, Args>
|
impl<State, Extractor, Args> FromRequestParts<State> for ValidEx<Extractor>
|
||||||
where
|
where
|
||||||
State: Send + Sync,
|
State: Send + Sync,
|
||||||
Args: Send
|
Args: Send + Sync + FromRef<State>,
|
||||||
+ Sync
|
|
||||||
+ FromRef<State>
|
|
||||||
+ for<'a> Arguments<'a, T = <Extractor as HasValidateArgs<'a>>::ValidateArgs>,
|
|
||||||
Extractor: for<'v> HasValidateArgs<'v> + FromRequestParts<State>,
|
Extractor: for<'v> HasValidateArgs<'v> + FromRequestParts<State>,
|
||||||
|
for<'v> <Extractor as HasValidateArgs<'v>>::ValidateArgs: ValidateArgs<'v, Args = &'v Args>,
|
||||||
{
|
{
|
||||||
type Rejection = ValidRejection<<Extractor as FromRequestParts<State>>::Rejection>;
|
type Rejection = ValidRejection<<Extractor as FromRequestParts<State>>::Rejection>;
|
||||||
|
|
||||||
@@ -249,8 +216,8 @@ where
|
|||||||
let inner = Extractor::from_request_parts(parts, state)
|
let inner = Extractor::from_request_parts(parts, state)
|
||||||
.await
|
.await
|
||||||
.map_err(ValidRejection::Inner)?;
|
.map_err(ValidRejection::Inner)?;
|
||||||
inner.get_validate_args().validate_args(arguments.get())?;
|
inner.get_validate_args().validate_with_args(&arguments)?;
|
||||||
Ok(ValidEx(inner, arguments))
|
Ok(ValidEx(inner))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,20 +245,22 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn valid_ex_deref_deref_mut_into_inner_arguments() {
|
fn valid_ex_deref_deref_mut_into_inner_arguments() {
|
||||||
let mut inner = String::from(TEST);
|
let mut inner = String::from(TEST);
|
||||||
let mut v = ValidEx(inner.clone(), ());
|
let mut v = ValidEx(inner.clone());
|
||||||
assert_eq!(&inner, v.deref());
|
assert_eq!(&inner, v.deref());
|
||||||
inner.push_str(TEST);
|
inner.push_str(TEST);
|
||||||
v.deref_mut().push_str(TEST);
|
v.deref_mut().push_str(TEST);
|
||||||
assert_eq!(&inner, v.deref());
|
assert_eq!(&inner, v.deref());
|
||||||
assert_eq!(inner, v.into_inner());
|
assert_eq!(inner, v.into_inner());
|
||||||
|
|
||||||
fn validate(_v: i32, _args: i32) -> Result<(), ValidationError> {
|
fn validate(v: &i32, args: &DataVA) -> Result<(), ValidationError> {
|
||||||
|
assert!(*v < args.a);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Validate)]
|
#[derive(Debug, Validate)]
|
||||||
|
#[validate(context = DataVA)]
|
||||||
struct Data {
|
struct Data {
|
||||||
#[validate(custom(function = "validate", arg = "i32"))]
|
#[validate(custom(function = "validate", use_context))]
|
||||||
v: i32,
|
v: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,21 +274,13 @@ pub mod tests {
|
|||||||
a: i32,
|
a: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Arguments<'a> for DataVA {
|
let v = 12;
|
||||||
type T = Data;
|
let data = Data { v };
|
||||||
|
let args = DataVA { a: v + 1 };
|
||||||
fn get(&'a self) -> <<Self as Arguments<'a>>::T as ValidateArgs<'a>>::Args {
|
let ve = ValidEx(data);
|
||||||
self.a
|
ve.validate_with_args(&args).expect("invalid");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = Data { v: 12 };
|
|
||||||
let args = DataVA { a: 123 };
|
|
||||||
let ve = ValidEx(data, args);
|
|
||||||
println!("{}", ve);
|
println!("{}", ve);
|
||||||
assert_eq!(ve.v, 12);
|
assert_eq!(ve.v, v);
|
||||||
let a = ve.arguments();
|
|
||||||
assert_eq!(a, 123);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#![cfg(feature = "validator")]
|
#![cfg(feature = "validator")]
|
||||||
|
|
||||||
use crate::tests::{ValidTest, ValidTestParameter};
|
use crate::tests::{ValidTest, ValidTestParameter};
|
||||||
use crate::{Arguments, HasValidate, HasValidateArgs, Valid, ValidEx, VALIDATION_ERROR_STATUS};
|
use crate::{HasValidate, HasValidateArgs, Valid, ValidEx, VALIDATION_ERROR_STATUS};
|
||||||
use axum::extract::{FromRef, Path, Query};
|
use axum::extract::{FromRef, Path, Query, State};
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::routing::{get, post};
|
use axum::routing::{get, post};
|
||||||
use axum::{Form, Json, Router};
|
use axum::{Form, Json, Router};
|
||||||
@@ -37,23 +37,28 @@ pub struct Parameters {
|
|||||||
feature = "typed_multipart",
|
feature = "typed_multipart",
|
||||||
derive(axum_typed_multipart::TryFromMultipart)
|
derive(axum_typed_multipart::TryFromMultipart)
|
||||||
)]
|
)]
|
||||||
|
#[validate(context = ParametersExValidationArguments)]
|
||||||
pub struct ParametersEx {
|
pub struct ParametersEx {
|
||||||
#[validate(custom(function = "validate_v0", arg = "&'v_a RangeInclusive<i32>"))]
|
#[validate(custom(function = "validate_v0", use_context))]
|
||||||
#[cfg_attr(feature = "extra_protobuf", prost(int32, tag = "1"))]
|
#[cfg_attr(feature = "extra_protobuf", prost(int32, tag = "1"))]
|
||||||
v0: i32,
|
v0: i32,
|
||||||
#[validate(custom(function = "validate_v1", arg = "&'v_a RangeInclusive<usize>"))]
|
#[validate(custom(function = "validate_v1", use_context))]
|
||||||
#[cfg_attr(feature = "extra_protobuf", prost(string, tag = "2"))]
|
#[cfg_attr(feature = "extra_protobuf", prost(string, tag = "2"))]
|
||||||
v1: String,
|
v1: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_v0(v: i32, args: &RangeInclusive<i32>) -> Result<(), ValidationError> {
|
fn validate_v0(v: &i32, args: &ParametersExValidationArguments) -> Result<(), ValidationError> {
|
||||||
args.contains(&v)
|
args.inner
|
||||||
|
.v0_range
|
||||||
|
.contains(v)
|
||||||
.then_some(())
|
.then_some(())
|
||||||
.ok_or_else(|| ValidationError::new("v0 is out of range"))
|
.ok_or_else(|| ValidationError::new("v0 is out of range"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_v1(v: &str, args: &RangeInclusive<usize>) -> Result<(), ValidationError> {
|
fn validate_v1(v: &str, args: &ParametersExValidationArguments) -> Result<(), ValidationError> {
|
||||||
args.contains(&v.len())
|
args.inner
|
||||||
|
.v1_length_range
|
||||||
|
.contains(&v.len())
|
||||||
.then_some(())
|
.then_some(())
|
||||||
.ok_or_else(|| ValidationError::new("v1 is invalid"))
|
.ok_or_else(|| ValidationError::new("v1 is invalid"))
|
||||||
}
|
}
|
||||||
@@ -69,13 +74,6 @@ pub struct ParametersExValidationArguments {
|
|||||||
inner: Arc<ParametersExValidationArgumentsInner>,
|
inner: Arc<ParametersExValidationArgumentsInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Arguments<'a> for ParametersExValidationArguments {
|
|
||||||
type T = ParametersEx;
|
|
||||||
fn get(&'a self) -> <ParametersEx as ValidateArgs<'a>>::Args {
|
|
||||||
(&self.inner.v0_range, &self.inner.v1_length_range)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ParametersExValidationArgumentsInner {
|
impl Default for ParametersExValidationArgumentsInner {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -146,12 +144,18 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let router = Router::new()
|
let router = Router::new()
|
||||||
.route(route::PATH, get(extract_path))
|
.route(route::PATH, get(extract_path))
|
||||||
|
.route(route::PATH_EX, get(extract_path_ex));
|
||||||
|
#[cfg(feature = "query")]
|
||||||
|
let router = router
|
||||||
.route(route::QUERY, get(extract_query))
|
.route(route::QUERY, get(extract_query))
|
||||||
|
.route(route::QUERY_EX, get(extract_query_ex));
|
||||||
|
#[cfg(feature = "form")]
|
||||||
|
let router = router
|
||||||
.route(route::FORM, post(extract_form))
|
.route(route::FORM, post(extract_form))
|
||||||
|
.route(route::FORM_EX, post(extract_form_ex));
|
||||||
|
#[cfg(feature = "json")]
|
||||||
|
let router = router
|
||||||
.route(route::JSON, post(extract_json))
|
.route(route::JSON, post(extract_json))
|
||||||
.route(route::PATH_EX, get(extract_path_ex))
|
|
||||||
.route(route::QUERY_EX, get(extract_query_ex))
|
|
||||||
.route(route::FORM_EX, post(extract_form_ex))
|
|
||||||
.route(route::JSON_EX, post(extract_json_ex));
|
.route(route::JSON_EX, post(extract_json_ex));
|
||||||
|
|
||||||
#[cfg(feature = "typed_header")]
|
#[cfg(feature = "typed_header")]
|
||||||
@@ -355,35 +359,44 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
test_extra_path(&test_executor, "path", &server_url).await?;
|
test_extra_path(&test_executor, "path", &server_url).await?;
|
||||||
test_extra_path(&test_executor, "path_ex", &server_url).await?;
|
test_extra_path(&test_executor, "path_ex", &server_url).await?;
|
||||||
|
|
||||||
// Valid
|
#[cfg(feature = "query")]
|
||||||
test_executor
|
{
|
||||||
.execute::<Query<Parameters>>(Method::GET, route::QUERY)
|
// Valid
|
||||||
.await?;
|
test_executor
|
||||||
|
.execute::<Query<Parameters>>(Method::GET, route::QUERY)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// ValidEx
|
// ValidEx
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<Query<Parameters>>(Method::GET, route::QUERY_EX)
|
.execute::<Query<Parameters>>(Method::GET, route::QUERY_EX)
|
||||||
.await?;
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
// Valid
|
#[cfg(feature = "form")]
|
||||||
test_executor
|
{
|
||||||
.execute::<Form<Parameters>>(Method::POST, route::FORM)
|
// Valid
|
||||||
.await?;
|
test_executor
|
||||||
|
.execute::<Form<Parameters>>(Method::POST, route::FORM)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// ValidEx
|
// ValidEx
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<Form<Parameters>>(Method::POST, route::FORM_EX)
|
.execute::<Form<Parameters>>(Method::POST, route::FORM_EX)
|
||||||
.await?;
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
// Valid
|
#[cfg(feature = "json")]
|
||||||
test_executor
|
{
|
||||||
.execute::<Json<Parameters>>(Method::POST, route::JSON)
|
// Valid
|
||||||
.await?;
|
test_executor
|
||||||
|
.execute::<Json<Parameters>>(Method::POST, route::JSON)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// ValidEx
|
// ValidEx
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<Json<Parameters>>(Method::POST, route::JSON_EX)
|
.execute::<Json<Parameters>>(Method::POST, route::JSON_EX)
|
||||||
.await?;
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "typed_header")]
|
#[cfg(feature = "typed_header")]
|
||||||
{
|
{
|
||||||
@@ -729,9 +742,10 @@ async fn extract_path(Valid(Path(parameters)): Valid<Path<Parameters>>) -> Statu
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_path_ex(
|
async fn extract_path_ex(
|
||||||
ValidEx(Path(parameters), args): ValidEx<Path<ParametersEx>, ParametersExValidationArguments>,
|
ValidEx(Path(parameters)): ValidEx<Path<ParametersEx>>,
|
||||||
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_query(Valid(Query(parameters)): Valid<Query<Parameters>>) -> StatusCode {
|
async fn extract_query(Valid(Query(parameters)): Valid<Query<Parameters>>) -> StatusCode {
|
||||||
@@ -739,9 +753,10 @@ async fn extract_query(Valid(Query(parameters)): Valid<Query<Parameters>>) -> St
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_query_ex(
|
async fn extract_query_ex(
|
||||||
ValidEx(Query(parameters), args): ValidEx<Query<ParametersEx>, ParametersExValidationArguments>,
|
ValidEx(Query(parameters)): ValidEx<Query<ParametersEx>>,
|
||||||
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_form(Valid(Form(parameters)): Valid<Form<Parameters>>) -> StatusCode {
|
async fn extract_form(Valid(Form(parameters)): Valid<Form<Parameters>>) -> StatusCode {
|
||||||
@@ -749,9 +764,10 @@ async fn extract_form(Valid(Form(parameters)): Valid<Form<Parameters>>) -> Statu
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_form_ex(
|
async fn extract_form_ex(
|
||||||
ValidEx(Form(parameters), args): ValidEx<Form<ParametersEx>, ParametersExValidationArguments>,
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
|
ValidEx(Form(parameters)): ValidEx<Form<ParametersEx>>,
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_json(Valid(Json(parameters)): Valid<Json<Parameters>>) -> StatusCode {
|
async fn extract_json(Valid(Json(parameters)): Valid<Json<Parameters>>) -> StatusCode {
|
||||||
@@ -759,9 +775,10 @@ async fn extract_json(Valid(Json(parameters)): Valid<Json<Parameters>>) -> Statu
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_json_ex(
|
async fn extract_json_ex(
|
||||||
ValidEx(Json(parameters), args): ValidEx<Json<ParametersEx>, ParametersExValidationArguments>,
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
|
ValidEx(Json(parameters)): ValidEx<Json<ParametersEx>>,
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_again<V: Validate>(validate: V) -> StatusCode {
|
fn validate_again<V: Validate>(validate: V) -> StatusCode {
|
||||||
@@ -783,7 +800,7 @@ fn validate_again_ex<'v, V: ValidateArgs<'v>>(
|
|||||||
// it should have returned `400 BAD REQUEST` if the `parameters` were invalid,
|
// it should have returned `400 BAD REQUEST` if the `parameters` were invalid,
|
||||||
// Let's validate them again to check if the `ValidEx` extractor works well.
|
// Let's validate them again to check if the `ValidEx` extractor works well.
|
||||||
// If it works properly, this function will never return `500 INTERNAL SERVER ERROR`
|
// If it works properly, this function will never return `500 INTERNAL SERVER ERROR`
|
||||||
match validate.validate_args(args) {
|
match validate.validate_with_args(args) {
|
||||||
Ok(_) => StatusCode::OK,
|
Ok(_) => StatusCode::OK,
|
||||||
Err(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
Err(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
}
|
}
|
||||||
@@ -798,7 +815,8 @@ mod typed_header {
|
|||||||
|
|
||||||
use super::{validate_again, Parameters};
|
use super::{validate_again, Parameters};
|
||||||
use super::{validate_again_ex, ParametersEx, ParametersExValidationArguments};
|
use super::{validate_again_ex, ParametersEx, ParametersExValidationArguments};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_extra::headers::{Error, Header, HeaderName, HeaderValue};
|
use axum_extra::headers::{Error, Header, HeaderName, HeaderValue};
|
||||||
use axum_extra::typed_header::TypedHeader;
|
use axum_extra::typed_header::TypedHeader;
|
||||||
@@ -812,12 +830,10 @@ mod typed_header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn extract_typed_header_ex(
|
pub(super) async fn extract_typed_header_ex(
|
||||||
ValidEx(TypedHeader(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
TypedHeader<ParametersEx>,
|
ValidEx(TypedHeader(parameters)): ValidEx<TypedHeader<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Header for Parameters {
|
impl Header for Parameters {
|
||||||
@@ -906,7 +922,8 @@ mod typed_multipart {
|
|||||||
validate_again, validate_again_ex, Parameters, ParametersEx,
|
validate_again, validate_again_ex, Parameters, ParametersEx,
|
||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_typed_multipart::{BaseMultipart, TypedMultipart, TypedMultipartError};
|
use axum_typed_multipart::{BaseMultipart, TypedMultipart, TypedMultipartError};
|
||||||
|
|
||||||
@@ -932,12 +949,10 @@ mod typed_multipart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn extract_typed_multipart_ex(
|
pub(super) async fn extract_typed_multipart_ex(
|
||||||
ValidEx(TypedMultipart(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
TypedMultipart<ParametersEx>,
|
ValidEx(TypedMultipart(parameters)): ValidEx<TypedMultipart<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn extract_base_multipart(
|
pub(super) async fn extract_base_multipart(
|
||||||
@@ -947,12 +962,12 @@ mod typed_multipart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn extract_base_multipart_ex(
|
pub(super) async fn extract_base_multipart_ex(
|
||||||
ValidEx(BaseMultipart { data, .. }, args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
|
ValidEx(BaseMultipart { data, .. }): ValidEx<
|
||||||
BaseMultipart<ParametersEx, TypedMultipartError>,
|
BaseMultipart<ParametersEx, TypedMultipartError>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
>,
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(data, args.get())
|
validate_again_ex(data, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -963,8 +978,8 @@ mod extra {
|
|||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::tests::{Rejection, ValidTest, ValidTestParameter};
|
use crate::tests::{Rejection, ValidTest, ValidTestParameter};
|
||||||
use crate::{Arguments, Valid, ValidEx, ValidRejection};
|
use crate::{Valid, ValidEx, ValidRejection};
|
||||||
use axum::extract::FromRequestParts;
|
use axum::extract::{FromRequestParts, State};
|
||||||
use axum::http::request::Parts;
|
use axum::http::request::Parts;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
@@ -1094,12 +1109,10 @@ mod extra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_cached_ex(
|
pub async fn extract_cached_ex(
|
||||||
ValidEx(Cached(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
Cached<ParametersEx>,
|
ValidEx(Cached(parameters)): ValidEx<Cached<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_with_rejection(
|
pub async fn extract_with_rejection(
|
||||||
@@ -1111,12 +1124,12 @@ mod extra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_with_rejection_ex(
|
pub async fn extract_with_rejection_ex(
|
||||||
ValidEx(WithRejection(parameters, _), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
|
ValidEx(WithRejection(parameters, _)): ValidEx<
|
||||||
WithRejection<ParametersEx, ValidWithRejectionRejection>,
|
WithRejection<ParametersEx, ValidWithRejectionRejection>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
>,
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WithRejectionValidRejection<E> {
|
pub struct WithRejectionValidRejection<E> {
|
||||||
@@ -1147,24 +1160,26 @@ mod extra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_with_rejection_valid_ex(
|
pub async fn extract_with_rejection_valid_ex(
|
||||||
WithRejection(ValidEx(parameters, args), _): WithRejection<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
ValidEx<ParametersEx, ParametersExValidationArguments>,
|
WithRejection(ValidEx(parameters), _): WithRejection<
|
||||||
|
ValidEx<ParametersEx>,
|
||||||
WithRejectionValidRejection<ParametersRejection>,
|
WithRejectionValidRejection<ParametersRejection>,
|
||||||
>,
|
>,
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "extra_typed_path")]
|
#[cfg(feature = "extra_typed_path")]
|
||||||
mod extra_typed_path {
|
mod extra_typed_path {
|
||||||
use super::{validate_again, validate_again_ex};
|
use super::{validate_again, validate_again_ex};
|
||||||
use crate::{Arguments, HasValidate, HasValidateArgs, Valid, ValidEx};
|
use crate::{HasValidate, HasValidateArgs, Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_extra::routing::TypedPath;
|
use axum_extra::routing::TypedPath;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
use validator::{Validate, ValidateArgs};
|
use validator::{Validate, ValidationError};
|
||||||
|
|
||||||
pub mod route {
|
pub mod route {
|
||||||
pub const EXTRA_TYPED_PATH: &str = "/extra_typed_path/:v0/:v1";
|
pub const EXTRA_TYPED_PATH: &str = "/extra_typed_path/:v0/:v1";
|
||||||
@@ -1192,12 +1207,33 @@ mod extra_typed_path {
|
|||||||
validate_again(param)
|
validate_again(param)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_v0(
|
||||||
|
v: &i32,
|
||||||
|
args: &TypedPathParamExValidationArguments,
|
||||||
|
) -> Result<(), ValidationError> {
|
||||||
|
args.v0_range
|
||||||
|
.contains(v)
|
||||||
|
.then_some(())
|
||||||
|
.ok_or_else(|| ValidationError::new("v0 is out of range"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_v1(
|
||||||
|
v: &str,
|
||||||
|
args: &TypedPathParamExValidationArguments,
|
||||||
|
) -> Result<(), ValidationError> {
|
||||||
|
args.v1_length_range
|
||||||
|
.contains(&v.len())
|
||||||
|
.then_some(())
|
||||||
|
.ok_or_else(|| ValidationError::new("v1 is invalid"))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Validate, TypedPath, Deserialize)]
|
#[derive(Validate, TypedPath, Deserialize)]
|
||||||
#[typed_path("/extra_typed_path_ex/:v0/:v1")]
|
#[typed_path("/extra_typed_path_ex/:v0/:v1")]
|
||||||
|
#[validate(context = TypedPathParamExValidationArguments)]
|
||||||
pub struct TypedPathParamEx {
|
pub struct TypedPathParamEx {
|
||||||
#[validate(custom(function = "super::validate_v0", arg = "&'v_a RangeInclusive<i32>"))]
|
#[validate(custom(function = "validate_v0", use_context))]
|
||||||
v0: i32,
|
v0: i32,
|
||||||
#[validate(custom(function = "super::validate_v1", arg = "&'v_a RangeInclusive<usize>"))]
|
#[validate(custom(function = "validate_v1", use_context))]
|
||||||
v1: String,
|
v1: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1224,17 +1260,11 @@ mod extra_typed_path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Arguments<'a> for TypedPathParamExValidationArguments {
|
|
||||||
type T = TypedPathParamEx;
|
|
||||||
fn get(&'a self) -> <TypedPathParamEx as ValidateArgs<'a>>::Args {
|
|
||||||
(&self.v0_range, &self.v1_length_range)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn extract_extra_typed_path_ex(
|
pub async fn extract_extra_typed_path_ex(
|
||||||
ValidEx(param, args): ValidEx<TypedPathParamEx, TypedPathParamExValidationArguments>,
|
State(arguments): State<TypedPathParamExValidationArguments>,
|
||||||
|
ValidEx(param): ValidEx<TypedPathParamEx>,
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(param, args.get())
|
validate_again_ex(param, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1244,7 +1274,8 @@ mod extra_query {
|
|||||||
validate_again, validate_again_ex, Parameters, ParametersEx,
|
validate_again, validate_again_ex, Parameters, ParametersEx,
|
||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_extra::extract::Query;
|
use axum_extra::extract::Query;
|
||||||
|
|
||||||
@@ -1260,12 +1291,10 @@ mod extra_query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_extra_query_ex(
|
pub async fn extract_extra_query_ex(
|
||||||
ValidEx(Query(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
Query<ParametersEx>,
|
ValidEx(Query(parameters)): ValidEx<Query<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1275,7 +1304,8 @@ mod extra_form {
|
|||||||
validate_again, validate_again_ex, Parameters, ParametersEx,
|
validate_again, validate_again_ex, Parameters, ParametersEx,
|
||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_extra::extract::Form;
|
use axum_extra::extract::Form;
|
||||||
|
|
||||||
@@ -1291,12 +1321,10 @@ mod extra_form {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_extra_form_ex(
|
pub async fn extract_extra_form_ex(
|
||||||
ValidEx(Form(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
Form<ParametersEx>,
|
ValidEx(Form(parameters)): ValidEx<Form<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1306,7 +1334,8 @@ mod extra_protobuf {
|
|||||||
validate_again, validate_again_ex, Parameters, ParametersEx,
|
validate_again, validate_again_ex, Parameters, ParametersEx,
|
||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_extra::protobuf::Protobuf;
|
use axum_extra::protobuf::Protobuf;
|
||||||
|
|
||||||
@@ -1322,12 +1351,10 @@ mod extra_protobuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_extra_protobuf_ex(
|
pub async fn extract_extra_protobuf_ex(
|
||||||
ValidEx(Protobuf(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
Protobuf<ParametersEx>,
|
ValidEx(Protobuf(parameters)): ValidEx<Protobuf<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1337,7 +1364,8 @@ mod yaml {
|
|||||||
validate_again, validate_again_ex, Parameters, ParametersEx,
|
validate_again, validate_again_ex, Parameters, ParametersEx,
|
||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_serde::Yaml;
|
use axum_serde::Yaml;
|
||||||
|
|
||||||
@@ -1351,12 +1379,10 @@ mod yaml {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_yaml_ex(
|
pub async fn extract_yaml_ex(
|
||||||
ValidEx(Yaml(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
Yaml<ParametersEx>,
|
ValidEx(Yaml(parameters)): ValidEx<Yaml<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1366,7 +1392,8 @@ mod msgpack {
|
|||||||
validate_again, validate_again_ex, Parameters, ParametersEx,
|
validate_again, validate_again_ex, Parameters, ParametersEx,
|
||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_serde::{MsgPack, MsgPackRaw};
|
use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
|
|
||||||
@@ -1384,12 +1411,10 @@ mod msgpack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_msgpack_ex(
|
pub async fn extract_msgpack_ex(
|
||||||
ValidEx(MsgPack(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
MsgPack<ParametersEx>,
|
ValidEx(MsgPack(parameters)): ValidEx<MsgPack<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_msgpack_raw(
|
pub async fn extract_msgpack_raw(
|
||||||
@@ -1399,12 +1424,10 @@ mod msgpack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_msgpack_raw_ex(
|
pub async fn extract_msgpack_raw_ex(
|
||||||
ValidEx(MsgPackRaw(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
MsgPackRaw<ParametersEx>,
|
ValidEx(MsgPackRaw(parameters)): ValidEx<MsgPackRaw<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1414,7 +1437,8 @@ mod xml {
|
|||||||
validate_again, validate_again_ex, Parameters, ParametersEx,
|
validate_again, validate_again_ex, Parameters, ParametersEx,
|
||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_serde::Xml;
|
use axum_serde::Xml;
|
||||||
|
|
||||||
@@ -1428,9 +1452,10 @@ mod xml {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_xml_ex(
|
pub async fn extract_xml_ex(
|
||||||
ValidEx(Xml(parameters), args): ValidEx<Xml<ParametersEx>, ParametersExValidationArguments>,
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
|
ValidEx(Xml(parameters)): ValidEx<Xml<ParametersEx>>,
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1440,7 +1465,8 @@ mod toml {
|
|||||||
validate_again, validate_again_ex, Parameters, ParametersEx,
|
validate_again, validate_again_ex, Parameters, ParametersEx,
|
||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_serde::Toml;
|
use axum_serde::Toml;
|
||||||
|
|
||||||
@@ -1454,12 +1480,10 @@ mod toml {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_toml_ex(
|
pub async fn extract_toml_ex(
|
||||||
ValidEx(Toml(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
Toml<ParametersEx>,
|
ValidEx(Toml(parameters)): ValidEx<Toml<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1469,7 +1493,8 @@ mod sonic {
|
|||||||
validate_again, validate_again_ex, Parameters, ParametersEx,
|
validate_again, validate_again_ex, Parameters, ParametersEx,
|
||||||
ParametersExValidationArguments,
|
ParametersExValidationArguments,
|
||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Valid, ValidEx};
|
||||||
|
use axum::extract::State;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_serde::Sonic;
|
use axum_serde::Sonic;
|
||||||
|
|
||||||
@@ -1483,11 +1508,9 @@ mod sonic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn extract_sonic_ex(
|
pub async fn extract_sonic_ex(
|
||||||
ValidEx(Sonic(parameters), args): ValidEx<
|
State(arguments): State<ParametersExValidationArguments>,
|
||||||
Sonic<ParametersEx>,
|
ValidEx(Sonic(parameters)): ValidEx<Sonic<ParametersEx>>,
|
||||||
ParametersExValidationArguments,
|
|
||||||
>,
|
|
||||||
) -> StatusCode {
|
) -> StatusCode {
|
||||||
validate_again_ex(parameters, args.get())
|
validate_again_ex(parameters, &arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user