axum_valid/extra/typed_path.rs
1//! # Support for `T: TypedPath` from `axum-extra`
2//!
3//! ## Feature
4//!
5//! Enable the `extra_typed_path` feature to use `Valid<T: TypedPath>`.
6//!
7//! ## Usage
8//!
9//! 1. Implement `TypedPath`, `Deserialize`, `Validate` and `HasValidate` for your data type `T`.
10//! 2. In your handler function, use `Valid<T>` as some parameter's type.
11//!
12//! ## Example
13//!
14//! ```no_run
15//! #[cfg(feature = "validator")]
16//! mod validator_example {
17//! use axum::Router;
18//! use axum_extra::routing::{RouterExt, TypedPath};
19//! use axum_valid::{HasValidate, Valid};
20//! use serde::Deserialize;
21//! use validator::Validate;
22//!
23//! pub fn router() -> Router {
24//! Router::new().typed_get(handler)
25//! }
26//!
27//! async fn handler(parameter: Valid<Parameter>) {
28//! assert!(parameter.validate().is_ok());
29//! }
30//!
31//! #[derive(TypedPath, Deserialize, Validate)]
32//! #[typed_path("/extra_typed_path/{v0}/{v1}")]
33//! struct Parameter {
34//! #[validate(range(min = 5, max = 10))]
35//! v0: i32,
36//! #[validate(length(min = 1, max = 10))]
37//! v1: String,
38//! }
39//!
40//! impl HasValidate for Parameter {
41//! type Validate = Self;
42//!
43//! fn get_validate(&self) -> &Self::Validate {
44//! self
45//! }
46//! }
47//! }
48//!
49//! #[cfg(feature = "garde")]
50//! mod garde_example {
51//! use axum::Router;
52//! use axum_extra::routing::{RouterExt, TypedPath};
53//! use axum_valid::{HasValidate, Garde};
54//! use serde::Deserialize;
55//! use garde::Validate;
56//!
57//! pub fn router() -> Router {
58//! Router::new().typed_get(handler)
59//! }
60//!
61//! async fn handler(parameter: Garde<Parameter>) {
62//! assert!(parameter.validate_with(&()).is_ok());
63//! }
64//!
65//! #[derive(TypedPath, Deserialize, Validate)]
66//! #[typed_path("/extra_typed_path/{v0}/{v1}")]
67//! struct Parameter {
68//! #[garde(range(min = 5, max = 10))]
69//! v0: i32,
70//! #[garde(length(min = 1, max = 10))]
71//! v1: String,
72//! }
73//!
74//! impl HasValidate for Parameter {
75//! type Validate = Self;
76//!
77//! fn get_validate(&self) -> &Self::Validate {
78//! self
79//! }
80//! }
81//! }
82//!
83//! # #[tokio::main]
84//! # async fn main() -> anyhow::Result<()> {
85//! # use std::net::SocketAddr;
86//! # use axum::Router;
87//! # use tokio::net::TcpListener;
88//! # let router = Router::new();
89//! # #[cfg(feature = "validator")]
90//! # let router = router.nest("/validator", validator_example::router());
91//! # #[cfg(feature = "garde")]
92//! # let router = router.nest("/garde", garde_example::router());
93//! # let listener = TcpListener::bind(&SocketAddr::from(([0u8, 0, 0, 0], 0u16))).await?;
94//! # axum::serve(listener, router.into_make_service())
95//! # .await?;
96//! # Ok(())
97//! # }
98//! ```
99
100#[cfg(feature = "garde")]
101use crate::Garde;
102#[cfg(feature = "validify")]
103use crate::{Modified, Validated, ValidifiedByRef};
104#[cfg(feature = "validator")]
105use crate::{Valid, ValidEx};
106#[cfg(any(feature = "validator", feature = "garde", feature = "validify"))]
107use axum_extra::routing::TypedPath;
108#[cfg(any(feature = "validator", feature = "garde", feature = "validify"))]
109use std::fmt::Display;
110
111#[cfg(feature = "validator")]
112impl<T: TypedPath + Display> TypedPath for Valid<T> {
113 const PATH: &'static str = T::PATH;
114}
115
116#[cfg(feature = "validator")]
117impl<T: TypedPath + Display> TypedPath for ValidEx<T> {
118 const PATH: &'static str = T::PATH;
119}
120
121#[cfg(feature = "garde")]
122impl<T: TypedPath + Display> TypedPath for Garde<T> {
123 const PATH: &'static str = T::PATH;
124}
125
126#[cfg(feature = "validify")]
127impl<T: TypedPath + Display> TypedPath for Validated<T> {
128 const PATH: &'static str = T::PATH;
129}
130
131#[cfg(feature = "validify")]
132impl<T: TypedPath + Display> TypedPath for Modified<T> {
133 const PATH: &'static str = T::PATH;
134}
135
136#[cfg(feature = "validify")]
137impl<T: TypedPath + Display> TypedPath for ValidifiedByRef<T> {
138 const PATH: &'static str = T::PATH;
139}