feat: add support extractors from axum-serde
This commit is contained in:
14
Cargo.toml
14
Cargo.toml
@@ -35,6 +35,10 @@ version = "0.9.0"
|
|||||||
default-features = false
|
default-features = false
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
|
[dependencies.axum-serde]
|
||||||
|
version = "0.1.0"
|
||||||
|
optional = true
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0.193"
|
version = "1.0.193"
|
||||||
optional = true
|
optional = true
|
||||||
@@ -48,7 +52,9 @@ reqwest = { version = "0.11.22", features = ["json", "multipart"] }
|
|||||||
serde = { version = "1.0.189", features = ["derive"] }
|
serde = { version = "1.0.189", features = ["derive"] }
|
||||||
validator = { version = "0.16.1", features = ["derive"] }
|
validator = { version = "0.16.1", features = ["derive"] }
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.107"
|
||||||
serde_yaml = "0.9.25"
|
serde_yaml = "0.9.27"
|
||||||
|
quick-xml = { version = "0.31.0", features = ["serialize"] }
|
||||||
|
toml = "0.8.8"
|
||||||
mime = "0.3.17"
|
mime = "0.3.17"
|
||||||
prost = "0.12.1"
|
prost = "0.12.1"
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.18.0"
|
||||||
@@ -64,6 +70,10 @@ json = ["axum/json"]
|
|||||||
form = ["axum/form"]
|
form = ["axum/form"]
|
||||||
query = ["axum/query"]
|
query = ["axum/query"]
|
||||||
typed_header = ["extra", "axum-extra/typed-header"]
|
typed_header = ["extra", "axum-extra/typed-header"]
|
||||||
|
msgpack = ["dep:axum-serde", "axum-serde/msgpack"]
|
||||||
|
yaml = ["dep:axum-serde", "axum-serde/yaml"]
|
||||||
|
xml = ["dep:axum-serde", "axum-serde/xml"]
|
||||||
|
toml = ["dep:axum-serde", "axum-serde/toml"]
|
||||||
into_json = ["json", "dep:serde"]
|
into_json = ["json", "dep:serde"]
|
||||||
422 = []
|
422 = []
|
||||||
extra = ["dep:axum-extra"]
|
extra = ["dep:axum-extra"]
|
||||||
@@ -72,7 +82,7 @@ extra_query = ["extra", "axum-extra/query"]
|
|||||||
extra_form = ["extra", "axum-extra/form"]
|
extra_form = ["extra", "axum-extra/form"]
|
||||||
extra_protobuf = ["extra", "axum-extra/protobuf"]
|
extra_protobuf = ["extra", "axum-extra/protobuf"]
|
||||||
all_extra_types = ["extra", "typed_header", "extra_typed_path", "extra_query", "extra_form", "extra_protobuf"]
|
all_extra_types = ["extra", "typed_header", "extra_typed_path", "extra_query", "extra_form", "extra_protobuf"]
|
||||||
all_types = ["json", "form", "query", "all_extra_types"]
|
all_types = ["json", "form", "query", "msgpack", "yaml", "xml", "all_extra_types"]
|
||||||
full_validator = ["validator", "all_types", "422", "into_json"]
|
full_validator = ["validator", "all_types", "422", "into_json"]
|
||||||
full_garde = ["garde", "all_types", "422", "into_json"]
|
full_garde = ["garde", "all_types", "422", "into_json"]
|
||||||
full_validify = ["validify", "all_types", "422", "into_json"]
|
full_validify = ["validify", "all_types", "422", "into_json"]
|
||||||
|
|||||||
@@ -440,6 +440,10 @@ Current module documentation predominantly showcases `Valid` examples, the usage
|
|||||||
| query | Enables support for `Query` | [`query`] | ✅ | ✅ | ✅ |
|
| query | Enables support for `Query` | [`query`] | ✅ | ✅ | ✅ |
|
||||||
| form | Enables support for `Form` | [`form`] | ✅ | ✅ | ✅ |
|
| form | Enables support for `Form` | [`form`] | ✅ | ✅ | ✅ |
|
||||||
| typed_header | Enables support for `TypedHeader` from `axum-extra` | [`typed_header`] | ❌ | ✅ | ✅ |
|
| typed_header | Enables support for `TypedHeader` from `axum-extra` | [`typed_header`] | ❌ | ✅ | ✅ |
|
||||||
|
| msgpack | Enables support for `MsgPack` and `MsgPackRaw` from `axum-serde` | [`msgpack`] | ❌ | ✅ | ✅ |
|
||||||
|
| yaml | Enables support for `Yaml` from `axum-serde` | [`yaml`] | ❌ | ✅ | ✅ |
|
||||||
|
| xml | Enables support for `Xml` from `axum-serde` | [`xml`] | ❌ | ✅ | ✅ |
|
||||||
|
| toml | Enables support for `Toml` from `axum-serde` | [`toml`] | ❌ | ✅ | ✅ |
|
||||||
| 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`] | ❌ | ✅ | ✅ |
|
||||||
@@ -472,6 +476,5 @@ This project is licensed under the MIT License.
|
|||||||
* [validify](https://crates.io/crates/validify)
|
* [validify](https://crates.io/crates/validify)
|
||||||
* [serde](https://crates.io/crates/serde)
|
* [serde](https://crates.io/crates/serde)
|
||||||
* [axum-extra](https://crates.io/crates/axum-extra)
|
* [axum-extra](https://crates.io/crates/axum-extra)
|
||||||
* [axum-yaml](https://crates.io/crates/axum-yaml)
|
* [axum-serde](https://crates.io/crates/axum-serde)
|
||||||
* [axum-msgpack](https://crates.io/crates/axum-msgpack)
|
|
||||||
* [axum_typed_multipart](https://crates.io/crates/axum_typed_multipart)
|
* [axum_typed_multipart](https://crates.io/crates/axum_typed_multipart)
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
#[cfg(feature = "yaml")]
|
#[cfg(feature = "yaml")]
|
||||||
{
|
{
|
||||||
use axum_yaml::Yaml;
|
use axum_serde::Yaml;
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<Yaml<ParametersGarde>>(Method::POST, yaml::route::YAML)
|
.execute::<Yaml<ParametersGarde>>(Method::POST, yaml::route::YAML)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -379,7 +379,7 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
#[cfg(feature = "msgpack")]
|
#[cfg(feature = "msgpack")]
|
||||||
{
|
{
|
||||||
use axum_msgpack::{MsgPack, MsgPackRaw};
|
use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<MsgPack<ParametersGarde>>(Method::POST, msgpack::route::MSGPACK)
|
.execute::<MsgPack<ParametersGarde>>(Method::POST, msgpack::route::MSGPACK)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -853,7 +853,7 @@ mod yaml {
|
|||||||
use super::{validate_again, ParametersGarde};
|
use super::{validate_again, ParametersGarde};
|
||||||
use crate::Garde;
|
use crate::Garde;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_yaml::Yaml;
|
use axum_serde::Yaml;
|
||||||
|
|
||||||
pub mod route {
|
pub mod route {
|
||||||
pub const YAML: &str = "/yaml";
|
pub const YAML: &str = "/yaml";
|
||||||
@@ -869,7 +869,7 @@ mod msgpack {
|
|||||||
use super::{validate_again, ParametersGarde};
|
use super::{validate_again, ParametersGarde};
|
||||||
use crate::Garde;
|
use crate::Garde;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_msgpack::{MsgPack, MsgPackRaw};
|
use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
|
|
||||||
pub mod route {
|
pub mod route {
|
||||||
pub const MSGPACK: &str = "/msgpack";
|
pub const MSGPACK: &str = "/msgpack";
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ pub mod form;
|
|||||||
pub mod garde;
|
pub mod garde;
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
pub mod json;
|
pub mod json;
|
||||||
|
#[cfg(feature = "msgpack")]
|
||||||
|
pub mod msgpack;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
#[cfg(feature = "query")]
|
#[cfg(feature = "query")]
|
||||||
pub mod query;
|
pub mod query;
|
||||||
@@ -18,6 +20,13 @@ pub mod typed_header;
|
|||||||
pub mod validator;
|
pub mod validator;
|
||||||
#[cfg(feature = "validify")]
|
#[cfg(feature = "validify")]
|
||||||
pub mod validify;
|
pub mod validify;
|
||||||
|
#[cfg(feature = "yaml")]
|
||||||
|
pub mod yaml;
|
||||||
|
|
||||||
|
#[cfg(feature = "toml")]
|
||||||
|
pub mod toml;
|
||||||
|
#[cfg(feature = "xml")]
|
||||||
|
pub mod xml;
|
||||||
|
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
|
|||||||
265
src/msgpack.rs
Normal file
265
src/msgpack.rs
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
//! # Support for `MsgPack<T>` and `MsgPackRaw<T>` from `axum-serde`
|
||||||
|
//!
|
||||||
|
//! ## Feature
|
||||||
|
//!
|
||||||
|
//! Enable the `msgpack` feature to use `Valid<MsgPack<T>>` and `Valid<MsgPackRaw<T>>`.
|
||||||
|
//!
|
||||||
|
//! ## Usage
|
||||||
|
//!
|
||||||
|
//! 1. Implement `Deserialize` and `Validate` for your data type `T`.
|
||||||
|
//! 2. In your handler function, use `Valid<MsgPack<T>>` or `Valid<MsgPackRaw<T>>` as some parameter's type.
|
||||||
|
//!
|
||||||
|
//! ## Example
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! #[cfg(feature = "validator")]
|
||||||
|
//! mod validator_example {
|
||||||
|
//! use axum::routing::post;
|
||||||
|
//! use axum::Json;
|
||||||
|
//! use axum::Router;
|
||||||
|
//! use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
|
//! use axum_valid::Valid;
|
||||||
|
//! use serde::Deserialize;
|
||||||
|
//! use validator::Validate;
|
||||||
|
//!
|
||||||
|
//! pub fn router() -> Router {
|
||||||
|
//! Router::new()
|
||||||
|
//! .route("/msgpack", post(handler))
|
||||||
|
//! .route("/msgpackraw", post(raw_handler))
|
||||||
|
//! }
|
||||||
|
//! async fn handler(Valid(MsgPack(parameter)): Valid<MsgPack<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate().is_ok());
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn raw_handler(Valid(MsgPackRaw(parameter)): Valid<MsgPackRaw<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate().is_ok());
|
||||||
|
//! }
|
||||||
|
//! #[derive(Validate, Deserialize)]
|
||||||
|
//! pub struct Parameter {
|
||||||
|
//! #[validate(range(min = 5, max = 10))]
|
||||||
|
//! pub v0: i32,
|
||||||
|
//! #[validate(length(min = 1, max = 10))]
|
||||||
|
//! pub v1: String,
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[cfg(feature = "garde")]
|
||||||
|
//! mod garde_example {
|
||||||
|
//! use axum::routing::post;
|
||||||
|
//! use axum::Router;
|
||||||
|
//! use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
|
//! use axum_valid::Garde;
|
||||||
|
//! use serde::Deserialize;
|
||||||
|
//! use garde::Validate;
|
||||||
|
//!
|
||||||
|
//! pub fn router() -> Router {
|
||||||
|
//! Router::new()
|
||||||
|
//! .route("/msgpack", post(handler))
|
||||||
|
//! .route("/msgpackraw", post(raw_handler))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn handler(Garde(MsgPack(parameter)): Garde<MsgPack<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate(&()).is_ok());
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn raw_handler(Garde(MsgPackRaw(parameter)): Garde<MsgPackRaw<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate(&()).is_ok());
|
||||||
|
//! }
|
||||||
|
//! #[derive(Validate, Deserialize)]
|
||||||
|
//! pub struct Parameter {
|
||||||
|
//! #[garde(range(min = 5, max = 10))]
|
||||||
|
//! pub v0: i32,
|
||||||
|
//! #[garde(length(min = 1, max = 10))]
|
||||||
|
//! pub v1: String,
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! # #[tokio::main]
|
||||||
|
//! # async fn main() -> anyhow::Result<()> {
|
||||||
|
//! # use std::net::SocketAddr;
|
||||||
|
//! # use axum::Router;
|
||||||
|
//! # use tokio::net::TcpListener;
|
||||||
|
//! # let router = Router::new();
|
||||||
|
//! # #[cfg(feature = "validator")]
|
||||||
|
//! # let router = router.nest("/validator", validator_example::router());
|
||||||
|
//! # #[cfg(feature = "garde")]
|
||||||
|
//! # let router = router.nest("/garde", garde_example::router());
|
||||||
|
//! # let listener = TcpListener::bind(&SocketAddr::from(([0u8, 0, 0, 0], 0u16))).await?;
|
||||||
|
//! # axum::serve(listener, router.into_make_service())
|
||||||
|
//! # .await?;
|
||||||
|
//! # Ok(())
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
|
||||||
|
use crate::HasValidate;
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
use crate::HasValidateArgs;
|
||||||
|
use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
use validator::ValidateArgs;
|
||||||
|
|
||||||
|
impl<T> HasValidate for MsgPack<T> {
|
||||||
|
type Validate = T;
|
||||||
|
fn get_validate(&self) -> &T {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
impl<'v, T: ValidateArgs<'v>> HasValidateArgs<'v> for MsgPack<T> {
|
||||||
|
type ValidateArgs = T;
|
||||||
|
fn get_validate_args(&self) -> &Self::ValidateArgs {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Modify> crate::HasModify for MsgPack<T> {
|
||||||
|
type Modify = T;
|
||||||
|
|
||||||
|
fn get_modify(&mut self) -> &mut Self::Modify {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T> crate::PayloadExtractor for MsgPack<T> {
|
||||||
|
type Payload = T;
|
||||||
|
|
||||||
|
fn get_payload(self) -> Self::Payload {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Validify> crate::HasValidify for MsgPack<T> {
|
||||||
|
type Validify = T;
|
||||||
|
type PayloadExtractor = MsgPack<T::Payload>;
|
||||||
|
fn from_validified(v: Self::Validify) -> Self {
|
||||||
|
MsgPack(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> HasValidate for MsgPackRaw<T> {
|
||||||
|
type Validate = T;
|
||||||
|
fn get_validate(&self) -> &T {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
impl<'v, T: ValidateArgs<'v>> HasValidateArgs<'v> for MsgPackRaw<T> {
|
||||||
|
type ValidateArgs = T;
|
||||||
|
fn get_validate_args(&self) -> &Self::ValidateArgs {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Modify> crate::HasModify for MsgPackRaw<T> {
|
||||||
|
type Modify = T;
|
||||||
|
|
||||||
|
fn get_modify(&mut self) -> &mut Self::Modify {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T> crate::PayloadExtractor for MsgPackRaw<T> {
|
||||||
|
type Payload = T;
|
||||||
|
|
||||||
|
fn get_payload(self) -> Self::Payload {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Validify> crate::HasValidify for MsgPackRaw<T> {
|
||||||
|
type Validify = T;
|
||||||
|
type PayloadExtractor = MsgPackRaw<T::Payload>;
|
||||||
|
fn from_validified(v: Self::Validify) -> Self {
|
||||||
|
MsgPackRaw(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::tests::{ValidTest, ValidTestParameter};
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
|
use reqwest::RequestBuilder;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
impl<T: ValidTestParameter + Serialize> ValidTest for MsgPack<T> {
|
||||||
|
const ERROR_STATUS_CODE: StatusCode = StatusCode::BAD_REQUEST;
|
||||||
|
|
||||||
|
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/msgpack")
|
||||||
|
.body(
|
||||||
|
rmp_serde::to_vec_named(T::valid())
|
||||||
|
.expect("Failed to serialize parameters to msgpack"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_error_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
#[derive(Serialize, Default)]
|
||||||
|
struct ErrorData {
|
||||||
|
error_field0: i32,
|
||||||
|
error_field1: Option<String>,
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/msgpack")
|
||||||
|
.body(
|
||||||
|
rmp_serde::to_vec(&ErrorData::default())
|
||||||
|
.expect("Failed to serialize parameters to msgpack"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_invalid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/msgpack")
|
||||||
|
.body(
|
||||||
|
rmp_serde::to_vec_named(T::invalid())
|
||||||
|
.expect("Failed to serialize parameters to msgpack"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ValidTestParameter + Serialize> ValidTest for MsgPackRaw<T> {
|
||||||
|
const ERROR_STATUS_CODE: StatusCode = StatusCode::BAD_REQUEST;
|
||||||
|
|
||||||
|
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/msgpack")
|
||||||
|
.body(
|
||||||
|
rmp_serde::to_vec(T::valid())
|
||||||
|
.expect("Failed to serialize parameters to msgpack"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_error_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
#[derive(Serialize, Default)]
|
||||||
|
struct ErrorData {
|
||||||
|
error_field0: i32,
|
||||||
|
error_field1: Option<String>,
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/msgpack")
|
||||||
|
.body(
|
||||||
|
rmp_serde::to_vec(&ErrorData::default())
|
||||||
|
.expect("Failed to serialize parameters to msgpack"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_invalid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/msgpack")
|
||||||
|
.body(
|
||||||
|
rmp_serde::to_vec(T::invalid())
|
||||||
|
.expect("Failed to serialize parameters to msgpack"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
174
src/toml.rs
Normal file
174
src/toml.rs
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
//! # Support for `Toml<T>` from `axum-serde`
|
||||||
|
//!
|
||||||
|
//! ## Feature
|
||||||
|
//!
|
||||||
|
//! Enable the `toml` feature to use `Valid<Toml<T>>`.
|
||||||
|
//!
|
||||||
|
//! ## Usage
|
||||||
|
//!
|
||||||
|
//! 1. Implement `Deserialize` and `Validate` for your data type `T`.
|
||||||
|
//! 2. In your handler function, use `Valid<Toml<T>>` as some parameter's type.
|
||||||
|
//!
|
||||||
|
//! ## Example
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! #[cfg(feature = "validator")]
|
||||||
|
//! mod validator_example {
|
||||||
|
//! use axum::routing::post;
|
||||||
|
//! use axum_serde::Toml;
|
||||||
|
//! use axum::Router;
|
||||||
|
//! use axum_valid::Valid;
|
||||||
|
//! use serde::Deserialize;
|
||||||
|
//! use validator::Validate;
|
||||||
|
//!
|
||||||
|
//! pub fn router() -> Router {
|
||||||
|
//! Router::new().route("/toml", post(handler))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn handler(Valid(Toml(parameter)): Valid<Toml<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate().is_ok());
|
||||||
|
//! // Support automatic dereferencing
|
||||||
|
//! println!("v0 = {}, v1 = {}", parameter.v0, parameter.v1);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[derive(Validate, Deserialize)]
|
||||||
|
//! pub struct Parameter {
|
||||||
|
//! #[validate(range(min = 5, max = 10))]
|
||||||
|
//! pub v0: i32,
|
||||||
|
//! #[validate(length(min = 1, max = 10))]
|
||||||
|
//! pub v1: String,
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[cfg(feature = "garde")]
|
||||||
|
//! mod garde_example {
|
||||||
|
//! use axum::routing::post;
|
||||||
|
//! use axum_serde::Toml;
|
||||||
|
//! use axum::Router;
|
||||||
|
//! use axum_valid::Garde;
|
||||||
|
//! use serde::Deserialize;
|
||||||
|
//! use garde::Validate;
|
||||||
|
//!
|
||||||
|
//! pub fn router() -> Router {
|
||||||
|
//! Router::new().route("/toml", post(handler))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn handler(Garde(Toml(parameter)): Garde<Toml<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate(&()).is_ok());
|
||||||
|
//! // Support automatic dereferencing
|
||||||
|
//! println!("v0 = {}, v1 = {}", parameter.v0, parameter.v1);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[derive(Validate, Deserialize)]
|
||||||
|
//! pub struct Parameter {
|
||||||
|
//! #[garde(range(min = 5, max = 10))]
|
||||||
|
//! pub v0: i32,
|
||||||
|
//! #[garde(length(min = 1, max = 10))]
|
||||||
|
//! pub v1: String,
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! # #[tokio::main]
|
||||||
|
//! # async fn main() -> anyhow::Result<()> {
|
||||||
|
//! # use std::net::SocketAddr;
|
||||||
|
//! # use axum::Router;
|
||||||
|
//! # use tokio::net::TcpListener;
|
||||||
|
//! # let router = Router::new();
|
||||||
|
//! # #[cfg(feature = "validator")]
|
||||||
|
//! # let router = router.nest("/validator", validator_example::router());
|
||||||
|
//! # #[cfg(feature = "garde")]
|
||||||
|
//! # let router = router.nest("/garde", garde_example::router());
|
||||||
|
//! # let listener = TcpListener::bind(&SocketAddr::from(([0u8, 0, 0, 0], 0u16))).await?;
|
||||||
|
//! # axum::serve(listener, router.into_make_service())
|
||||||
|
//! # .await?;
|
||||||
|
//! # Ok(())
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use crate::HasValidate;
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
use crate::HasValidateArgs;
|
||||||
|
use axum_serde::Toml;
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
use validator::ValidateArgs;
|
||||||
|
|
||||||
|
impl<T> HasValidate for Toml<T> {
|
||||||
|
type Validate = T;
|
||||||
|
fn get_validate(&self) -> &T {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
impl<'v, T: ValidateArgs<'v>> HasValidateArgs<'v> for Toml<T> {
|
||||||
|
type ValidateArgs = T;
|
||||||
|
fn get_validate_args(&self) -> &Self::ValidateArgs {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Modify> crate::HasModify for Toml<T> {
|
||||||
|
type Modify = T;
|
||||||
|
|
||||||
|
fn get_modify(&mut self) -> &mut Self::Modify {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T> crate::PayloadExtractor for Toml<T> {
|
||||||
|
type Payload = T;
|
||||||
|
|
||||||
|
fn get_payload(self) -> Self::Payload {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Validify> crate::HasValidify for Toml<T> {
|
||||||
|
type Validify = T;
|
||||||
|
type PayloadExtractor = Toml<T::Payload>;
|
||||||
|
fn from_validified(v: Self::Validify) -> Self {
|
||||||
|
Toml(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::tests::{ValidTest, ValidTestParameter};
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum_serde::Toml;
|
||||||
|
use reqwest::RequestBuilder;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
impl<T: ValidTestParameter + Serialize> ValidTest for Toml<T> {
|
||||||
|
const ERROR_STATUS_CODE: StatusCode = StatusCode::UNPROCESSABLE_ENTITY;
|
||||||
|
|
||||||
|
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/toml")
|
||||||
|
.body(toml::to_string(&T::valid()).expect("Failed to serialize parameters to toml"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_error_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
#[derive(Serialize, Default)]
|
||||||
|
struct ErrorData {
|
||||||
|
error_field: i32,
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/toml")
|
||||||
|
.body(
|
||||||
|
toml::to_string(&ErrorData::default())
|
||||||
|
.expect("Failed to serialize parameters to toml"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_invalid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/toml")
|
||||||
|
.body(
|
||||||
|
toml::to_string(&T::invalid()).expect("Failed to serialize parameters to toml"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -550,7 +550,7 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
#[cfg(feature = "yaml")]
|
#[cfg(feature = "yaml")]
|
||||||
{
|
{
|
||||||
use axum_yaml::Yaml;
|
use axum_serde::Yaml;
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<Yaml<Parameters>>(Method::POST, yaml::route::YAML)
|
.execute::<Yaml<Parameters>>(Method::POST, yaml::route::YAML)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -561,7 +561,7 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
#[cfg(feature = "msgpack")]
|
#[cfg(feature = "msgpack")]
|
||||||
{
|
{
|
||||||
use axum_msgpack::{MsgPack, MsgPackRaw};
|
use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<MsgPack<Parameters>>(Method::POST, msgpack::route::MSGPACK)
|
.execute::<MsgPack<Parameters>>(Method::POST, msgpack::route::MSGPACK)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -1284,7 +1284,7 @@ mod yaml {
|
|||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Arguments, Valid, ValidEx};
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_yaml::Yaml;
|
use axum_serde::Yaml;
|
||||||
|
|
||||||
pub mod route {
|
pub mod route {
|
||||||
pub const YAML: &str = "/yaml";
|
pub const YAML: &str = "/yaml";
|
||||||
@@ -1313,7 +1313,7 @@ mod msgpack {
|
|||||||
};
|
};
|
||||||
use crate::{Arguments, Valid, ValidEx};
|
use crate::{Arguments, Valid, ValidEx};
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_msgpack::{MsgPack, MsgPackRaw};
|
use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
|
|
||||||
pub mod route {
|
pub mod route {
|
||||||
pub const MSGPACK: &str = "/msgpack";
|
pub const MSGPACK: &str = "/msgpack";
|
||||||
|
|||||||
@@ -828,7 +828,7 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
#[cfg(feature = "yaml")]
|
#[cfg(feature = "yaml")]
|
||||||
{
|
{
|
||||||
use axum_yaml::Yaml;
|
use axum_serde::Yaml;
|
||||||
|
|
||||||
// Validated
|
// Validated
|
||||||
test_executor
|
test_executor
|
||||||
@@ -853,7 +853,7 @@ async fn test_main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
#[cfg(feature = "msgpack")]
|
#[cfg(feature = "msgpack")]
|
||||||
{
|
{
|
||||||
use axum_msgpack::{MsgPack, MsgPackRaw};
|
use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
// Validated
|
// Validated
|
||||||
test_executor
|
test_executor
|
||||||
.execute::<MsgPack<ParametersValidify>>(Method::POST, msgpack::route::MSGPACK)
|
.execute::<MsgPack<ParametersValidify>>(Method::POST, msgpack::route::MSGPACK)
|
||||||
@@ -1770,7 +1770,7 @@ mod yaml {
|
|||||||
use super::{check_modified, check_validated, check_validified, ParametersValidify};
|
use super::{check_modified, check_validated, check_validified, ParametersValidify};
|
||||||
use crate::{Modified, Validated, Validified, ValidifiedByRef};
|
use crate::{Modified, Validated, Validified, ValidifiedByRef};
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_yaml::Yaml;
|
use axum_serde::Yaml;
|
||||||
|
|
||||||
pub mod route {
|
pub mod route {
|
||||||
pub const YAML: &str = "/yaml";
|
pub const YAML: &str = "/yaml";
|
||||||
@@ -1809,7 +1809,7 @@ mod msgpack {
|
|||||||
use super::{check_modified, check_validated, check_validified, ParametersValidify};
|
use super::{check_modified, check_validated, check_validified, ParametersValidify};
|
||||||
use crate::{Modified, Validated, Validified, ValidifiedByRef};
|
use crate::{Modified, Validated, Validified, ValidifiedByRef};
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum_msgpack::{MsgPack, MsgPackRaw};
|
use axum_serde::{MsgPack, MsgPackRaw};
|
||||||
|
|
||||||
pub mod route {
|
pub mod route {
|
||||||
pub const MSGPACK: &str = "/msgpack";
|
pub const MSGPACK: &str = "/msgpack";
|
||||||
|
|||||||
178
src/xml.rs
Normal file
178
src/xml.rs
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
//! # Support for `Xml<T>` from `axum-serde`
|
||||||
|
//!
|
||||||
|
//! ## Feature
|
||||||
|
//!
|
||||||
|
//! Enable the `Xml` feature to use `Valid<Xml<T>>`.
|
||||||
|
//!
|
||||||
|
//! ## Usage
|
||||||
|
//!
|
||||||
|
//! 1. Implement `Deserialize` and `Validate` for your data type `T`.
|
||||||
|
//! 2. In your handler function, use `Valid<Xml<T>>` as some parameter's type.
|
||||||
|
//!
|
||||||
|
//! ## Example
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! #[cfg(feature = "validator")]
|
||||||
|
//! mod validator_example {
|
||||||
|
//! use axum::routing::post;
|
||||||
|
//! use axum_serde::Xml;
|
||||||
|
//! use axum::Router;
|
||||||
|
//! use axum_valid::Valid;
|
||||||
|
//! use serde::Deserialize;
|
||||||
|
//! use validator::Validate;
|
||||||
|
//!
|
||||||
|
//! pub fn router() -> Router {
|
||||||
|
//! Router::new().route("/Xml", post(handler))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn handler(Valid(Xml(parameter)): Valid<Xml<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate().is_ok());
|
||||||
|
//! // Support automatic dereferencing
|
||||||
|
//! println!("v0 = {}, v1 = {}", parameter.v0, parameter.v1);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[derive(Validate, Deserialize)]
|
||||||
|
//! pub struct Parameter {
|
||||||
|
//! #[validate(range(min = 5, max = 10))]
|
||||||
|
//! pub v0: i32,
|
||||||
|
//! #[validate(length(min = 1, max = 10))]
|
||||||
|
//! pub v1: String,
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[cfg(feature = "garde")]
|
||||||
|
//! mod garde_example {
|
||||||
|
//! use axum::routing::post;
|
||||||
|
//! use axum_serde::Xml;
|
||||||
|
//! use axum::Router;
|
||||||
|
//! use axum_valid::Garde;
|
||||||
|
//! use serde::Deserialize;
|
||||||
|
//! use garde::Validate;
|
||||||
|
//!
|
||||||
|
//! pub fn router() -> Router {
|
||||||
|
//! Router::new().route("/Xml", post(handler))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn handler(Garde(Xml(parameter)): Garde<Xml<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate(&()).is_ok());
|
||||||
|
//! // Support automatic dereferencing
|
||||||
|
//! println!("v0 = {}, v1 = {}", parameter.v0, parameter.v1);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[derive(Validate, Deserialize)]
|
||||||
|
//! pub struct Parameter {
|
||||||
|
//! #[garde(range(min = 5, max = 10))]
|
||||||
|
//! pub v0: i32,
|
||||||
|
//! #[garde(length(min = 1, max = 10))]
|
||||||
|
//! pub v1: String,
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! # #[tokio::main]
|
||||||
|
//! # async fn main() -> anyhow::Result<()> {
|
||||||
|
//! # use std::net::SocketAddr;
|
||||||
|
//! # use axum::Router;
|
||||||
|
//! # use tokio::net::TcpListener;
|
||||||
|
//! # let router = Router::new();
|
||||||
|
//! # #[cfg(feature = "validator")]
|
||||||
|
//! # let router = router.nest("/validator", validator_example::router());
|
||||||
|
//! # #[cfg(feature = "garde")]
|
||||||
|
//! # let router = router.nest("/garde", garde_example::router());
|
||||||
|
//! # let listener = TcpListener::bind(&SocketAddr::from(([0u8, 0, 0, 0], 0u16))).await?;
|
||||||
|
//! # axum::serve(listener, router.into_make_service())
|
||||||
|
//! # .await?;
|
||||||
|
//! # Ok(())
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use crate::HasValidate;
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
use crate::HasValidateArgs;
|
||||||
|
use axum_serde::Xml;
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
use validator::ValidateArgs;
|
||||||
|
|
||||||
|
impl<T> HasValidate for Xml<T> {
|
||||||
|
type Validate = T;
|
||||||
|
fn get_validate(&self) -> &T {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
impl<'v, T: ValidateArgs<'v>> HasValidateArgs<'v> for Xml<T> {
|
||||||
|
type ValidateArgs = T;
|
||||||
|
fn get_validate_args(&self) -> &Self::ValidateArgs {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Modify> crate::HasModify for Xml<T> {
|
||||||
|
type Modify = T;
|
||||||
|
|
||||||
|
fn get_modify(&mut self) -> &mut Self::Modify {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T> crate::PayloadExtractor for Xml<T> {
|
||||||
|
type Payload = T;
|
||||||
|
|
||||||
|
fn get_payload(self) -> Self::Payload {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Validify> crate::HasValidify for Xml<T> {
|
||||||
|
type Validify = T;
|
||||||
|
type PayloadExtractor = Xml<T::Payload>;
|
||||||
|
fn from_validified(v: Self::Validify) -> Self {
|
||||||
|
Xml(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::tests::{ValidTest, ValidTestParameter};
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum_serde::Xml;
|
||||||
|
use reqwest::RequestBuilder;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
impl<T: ValidTestParameter + Serialize> ValidTest for Xml<T> {
|
||||||
|
const ERROR_STATUS_CODE: StatusCode = StatusCode::UNPROCESSABLE_ENTITY;
|
||||||
|
|
||||||
|
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/xml")
|
||||||
|
.body(
|
||||||
|
quick_xml::se::to_string(&T::valid())
|
||||||
|
.expect("Failed to serialize parameters to xml"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_error_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
#[derive(Serialize, Default)]
|
||||||
|
struct ErrorData {
|
||||||
|
error_field: i32,
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/xml")
|
||||||
|
.body(
|
||||||
|
quick_xml::se::to_string(&ErrorData::default())
|
||||||
|
.expect("Failed to serialize parameters to xml"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_invalid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/xml")
|
||||||
|
.body(
|
||||||
|
quick_xml::se::to_string(&T::invalid())
|
||||||
|
.expect("Failed to serialize parameters to xml"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
178
src/yaml.rs
Normal file
178
src/yaml.rs
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
//! # Support for `Yaml<T>` from `axum-serde`
|
||||||
|
//!
|
||||||
|
//! ## Feature
|
||||||
|
//!
|
||||||
|
//! Enable the `yaml` feature to use `Valid<Yaml<T>>`.
|
||||||
|
//!
|
||||||
|
//! ## Usage
|
||||||
|
//!
|
||||||
|
//! 1. Implement `Deserialize` and `Validate` for your data type `T`.
|
||||||
|
//! 2. In your handler function, use `Valid<Yaml<T>>` as some parameter's type.
|
||||||
|
//!
|
||||||
|
//! ## Example
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! #[cfg(feature = "validator")]
|
||||||
|
//! mod validator_example {
|
||||||
|
//! use axum::routing::post;
|
||||||
|
//! use axum_serde::Yaml;
|
||||||
|
//! use axum::Router;
|
||||||
|
//! use axum_valid::Valid;
|
||||||
|
//! use serde::Deserialize;
|
||||||
|
//! use validator::Validate;
|
||||||
|
//!
|
||||||
|
//! pub fn router() -> Router {
|
||||||
|
//! Router::new().route("/yaml", post(handler))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn handler(Valid(Yaml(parameter)): Valid<Yaml<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate().is_ok());
|
||||||
|
//! // Support automatic dereferencing
|
||||||
|
//! println!("v0 = {}, v1 = {}", parameter.v0, parameter.v1);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[derive(Validate, Deserialize)]
|
||||||
|
//! pub struct Parameter {
|
||||||
|
//! #[validate(range(min = 5, max = 10))]
|
||||||
|
//! pub v0: i32,
|
||||||
|
//! #[validate(length(min = 1, max = 10))]
|
||||||
|
//! pub v1: String,
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[cfg(feature = "garde")]
|
||||||
|
//! mod garde_example {
|
||||||
|
//! use axum::routing::post;
|
||||||
|
//! use axum_serde::Yaml;
|
||||||
|
//! use axum::Router;
|
||||||
|
//! use axum_valid::Garde;
|
||||||
|
//! use serde::Deserialize;
|
||||||
|
//! use garde::Validate;
|
||||||
|
//!
|
||||||
|
//! pub fn router() -> Router {
|
||||||
|
//! Router::new().route("/yaml", post(handler))
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn handler(Garde(Yaml(parameter)): Garde<Yaml<Parameter>>) {
|
||||||
|
//! assert!(parameter.validate(&()).is_ok());
|
||||||
|
//! // Support automatic dereferencing
|
||||||
|
//! println!("v0 = {}, v1 = {}", parameter.v0, parameter.v1);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[derive(Validate, Deserialize)]
|
||||||
|
//! pub struct Parameter {
|
||||||
|
//! #[garde(range(min = 5, max = 10))]
|
||||||
|
//! pub v0: i32,
|
||||||
|
//! #[garde(length(min = 1, max = 10))]
|
||||||
|
//! pub v1: String,
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! # #[tokio::main]
|
||||||
|
//! # async fn main() -> anyhow::Result<()> {
|
||||||
|
//! # use std::net::SocketAddr;
|
||||||
|
//! # use axum::Router;
|
||||||
|
//! # use tokio::net::TcpListener;
|
||||||
|
//! # let router = Router::new();
|
||||||
|
//! # #[cfg(feature = "validator")]
|
||||||
|
//! # let router = router.nest("/validator", validator_example::router());
|
||||||
|
//! # #[cfg(feature = "garde")]
|
||||||
|
//! # let router = router.nest("/garde", garde_example::router());
|
||||||
|
//! # let listener = TcpListener::bind(&SocketAddr::from(([0u8, 0, 0, 0], 0u16))).await?;
|
||||||
|
//! # axum::serve(listener, router.into_make_service())
|
||||||
|
//! # .await?;
|
||||||
|
//! # Ok(())
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use crate::HasValidate;
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
use crate::HasValidateArgs;
|
||||||
|
use axum_serde::Yaml;
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
use validator::ValidateArgs;
|
||||||
|
|
||||||
|
impl<T> HasValidate for Yaml<T> {
|
||||||
|
type Validate = T;
|
||||||
|
fn get_validate(&self) -> &T {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
impl<'v, T: ValidateArgs<'v>> HasValidateArgs<'v> for Yaml<T> {
|
||||||
|
type ValidateArgs = T;
|
||||||
|
fn get_validate_args(&self) -> &Self::ValidateArgs {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Modify> crate::HasModify for Yaml<T> {
|
||||||
|
type Modify = T;
|
||||||
|
|
||||||
|
fn get_modify(&mut self) -> &mut Self::Modify {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T> crate::PayloadExtractor for Yaml<T> {
|
||||||
|
type Payload = T;
|
||||||
|
|
||||||
|
fn get_payload(self) -> Self::Payload {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "validify")]
|
||||||
|
impl<T: validify::Validify> crate::HasValidify for Yaml<T> {
|
||||||
|
type Validify = T;
|
||||||
|
type PayloadExtractor = Yaml<T::Payload>;
|
||||||
|
fn from_validified(v: Self::Validify) -> Self {
|
||||||
|
Yaml(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::tests::{ValidTest, ValidTestParameter};
|
||||||
|
use axum::http::StatusCode;
|
||||||
|
use axum_serde::Yaml;
|
||||||
|
use reqwest::RequestBuilder;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
impl<T: ValidTestParameter + Serialize> ValidTest for Yaml<T> {
|
||||||
|
const ERROR_STATUS_CODE: StatusCode = StatusCode::UNPROCESSABLE_ENTITY;
|
||||||
|
|
||||||
|
fn set_valid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/yaml")
|
||||||
|
.body(
|
||||||
|
serde_yaml::to_string(&T::valid())
|
||||||
|
.expect("Failed to serialize parameters to yaml"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_error_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
#[derive(Serialize, Default)]
|
||||||
|
struct ErrorData {
|
||||||
|
error_field: i32,
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/yaml")
|
||||||
|
.body(
|
||||||
|
serde_yaml::to_string(&ErrorData::default())
|
||||||
|
.expect("Failed to serialize parameters to yaml"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_invalid_request(builder: RequestBuilder) -> RequestBuilder {
|
||||||
|
builder
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/yaml")
|
||||||
|
.body(
|
||||||
|
serde_yaml::to_string(&T::invalid())
|
||||||
|
.expect("Failed to serialize parameters to yaml"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user