• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gengteng / axum-valid / 6586130410

20 Oct 2023 09:46AM UTC coverage: 82.548% (-6.7%) from 89.277%
6586130410

push

github

gengteng
add support for validify

214 of 214 new or added lines in 7 files covered. (100.0%)

1173 of 1421 relevant lines covered (82.55%)

12.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.68
/src/validator.rs
1
//! # Validator support
2
//!
3
//! ## Feature
4
//!
5
//! Enable the `validator` feature (enabled by default) to use `Valid<E>` and `ValidEx<E, A>`.
6
//!
7

8
#[cfg(test)]
9
pub mod test;
10

11
use crate::{HasValidate, ValidationRejection};
12
use axum::async_trait;
13
use axum::extract::{FromRef, FromRequest, FromRequestParts};
14
use axum::http::request::Parts;
15
use axum::http::Request;
16
use std::fmt::Display;
17
use std::ops::{Deref, DerefMut};
18
use validator::{Validate, ValidateArgs, ValidationErrors};
19

20
/// # `Valid` data extractor
21
///
22
/// This extractor can be used in combination with axum's extractors like
23
/// Json, Form, Query, Path, etc to validate their inner data automatically.
24
/// It can also work with custom extractors that implement the `HasValidate` trait.
25
///
26
/// See the docs for each integration module to find examples of using
27
/// `Valid` with that extractor.
28
///
29
/// For examples with custom extractors, check out the `tests/custom.rs` file.
30
///
31
#[derive(Debug, Clone, Copy, Default)]
32
pub struct Valid<E>(pub E);
33

34
impl<E> Deref for Valid<E> {
35
    type Target = E;
36

37
    fn deref(&self) -> &Self::Target {
4✔
38
        &self.0
×
39
    }
40
}
41

42
impl<E> DerefMut for Valid<E> {
43
    fn deref_mut(&mut self) -> &mut Self::Target {
4✔
44
        &mut self.0
×
45
    }
46
}
47

48
impl<T: Display, A> Display for ValidEx<T, A> {
49
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4✔
50
        self.0.fmt(f)
4✔
51
    }
52
}
53

54
impl<E> Valid<E> {
×
55
    /// Consume the `Valid` extractor and returns the inner type.
56
    pub fn into_inner(self) -> E {
4✔
57
        self.0
4✔
58
    }
59
}
60

61
/// # `ValidEx` data extractor
62
///
63
/// `ValidEx` can be incorporated with extractors from various modules, similar to `Valid`.
64
/// Two differences exist between `ValidEx` and `Valid`:
65
///
66
/// - The inner data type in `ValidEx` implements `ValidateArgs` instead of `Validate`.
67
/// - `ValidEx` includes a second field that represents arguments used during validation of the first field.
68
///
69
/// The implementation of `ValidateArgs` is often automatically handled by validator's derive macros
70
/// (for more details, please refer to the validator's documentation).
71
///
72
/// Although current module documentation predominantly showcases `Valid` examples, the usage of `ValidEx` is analogous.
73
///
74
#[derive(Debug, Clone, Copy, Default)]
75
pub struct ValidEx<E, A>(pub E, pub A);
76

77
impl<E, A> Deref for ValidEx<E, A> {
×
78
    type Target = E;
79

80
    fn deref(&self) -> &Self::Target {
8✔
81
        &self.0
×
82
    }
83
}
84

85
impl<E, A> DerefMut for ValidEx<E, A> {
86
    fn deref_mut(&mut self) -> &mut Self::Target {
4✔
87
        &mut self.0
×
88
    }
89
}
90

91
impl<T: Display> Display for Valid<T> {
92
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4✔
93
        self.0.fmt(f)
4✔
94
    }
95
}
96

97
impl<E, A> ValidEx<E, A> {
×
98
    /// Consumes the `ValidEx` and returns the validated data within.
99
    ///
100
    /// This returns the `E` type which represents the data that has been
101
    /// successfully validated.
102
    pub fn into_inner(self) -> E {
4✔
103
        self.0
4✔
104
    }
105

106
    /// Returns a reference to the validation arguments.
107
    ///
108
    /// This provides access to the `A` type which contains the arguments used
109
    /// to validate the data. These arguments were passed to the validation
110
    /// function.
111
    pub fn arguments<'a>(&'a self) -> <<A as Arguments<'a>>::T as ValidateArgs<'a>>::Args
4✔
112
    where
113
        A: Arguments<'a>,
114
    {
115
        self.1.get()
4✔
116
    }
117
}
118

119
/// `Arguments` provides the validation arguments for the data type `T`.
120
///
121
/// This trait has an associated type `T` which represents the data type to
122
/// validate. `T` must implement the `ValidateArgs` trait which defines the
123
/// validation logic.
124
///
125
/// It's important to mention that types implementing `Arguments` should be a part of the router's state
126
/// (either through implementing `FromRef<StateType>` or by directly becoming the state)
127
/// to enable automatic arguments retrieval during validation.
128
///
129
pub trait Arguments<'a> {
130
    /// The data type to validate using this arguments
131
    type T: ValidateArgs<'a>;
×
132
    /// This method gets the arguments required by `ValidateArgs::validate_args`
133
    fn get(&'a self) -> <<Self as Arguments<'a>>::T as ValidateArgs<'a>>::Args;
134
}
135

136
/// `ValidRejection` is returned when the `Valid` or `ValidEx` extractor fails.
137
///
138
pub type ValidRejection<E> = ValidationRejection<ValidationErrors, E>;
×
139

140
impl<E> From<ValidationErrors> for ValidRejection<E> {
141
    fn from(value: ValidationErrors) -> Self {
47✔
142
        Self::Valid(value)
47✔
143
    }
144
}
145

146
/// Trait for types that can supply a reference that can be validated using arguments.
147
///
148
/// Extractor types `T` that implement this trait can be used with `ValidEx`.
149
///
150
pub trait HasValidateArgs<'v> {
151
    /// Inner type that can be validated using arguments
152
    type ValidateArgs: ValidateArgs<'v>;
×
153
    /// Get the inner value
154
    fn get_validate_args(&self) -> &Self::ValidateArgs;
155
}
156

157
#[async_trait]
158
impl<State, Body, Extractor> FromRequest<State, Body> for Valid<Extractor>
×
159
where
160
    State: Send + Sync,
161
    Body: Send + Sync + 'static,
162
    Extractor: HasValidate + FromRequest<State, Body>,
163
    Extractor::Validate: Validate,
164
{
165
    type Rejection = ValidRejection<<Extractor as FromRequest<State, Body>>::Rejection>;
166

167
    async fn from_request(req: Request<Body>, state: &State) -> Result<Self, Self::Rejection> {
174✔
168
        let inner = Extractor::from_request(req, state)
145✔
169
            .await
58✔
170
            .map_err(ValidRejection::Inner)?;
29✔
171
        inner.get_validate().validate()?;
87✔
172
        Ok(Valid(inner))
29✔
173
    }
174
}
175

176
#[async_trait]
177
impl<State, Extractor> FromRequestParts<State> for Valid<Extractor>
×
178
where
179
    State: Send + Sync,
180
    Extractor: HasValidate + FromRequestParts<State>,
181
    Extractor::Validate: Validate,
182
{
183
    type Rejection = ValidRejection<<Extractor as FromRequestParts<State>>::Rejection>;
184

185
    async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> {
150✔
186
        let inner = Extractor::from_request_parts(parts, state)
144✔
187
            .await
60✔
188
            .map_err(ValidRejection::Inner)?;
27✔
189
        inner.get_validate().validate()?;
90✔
190
        Ok(Valid(inner))
30✔
191
    }
192
}
193

194
#[async_trait]
195
impl<State, Body, Extractor, Args> FromRequest<State, Body> for ValidEx<Extractor, Args>
×
196
where
197
    State: Send + Sync,
198
    Body: Send + Sync + 'static,
199
    Args: Send
200
        + Sync
201
        + FromRef<State>
202
        + for<'a> Arguments<'a, T = <Extractor as HasValidateArgs<'a>>::ValidateArgs>,
203
    Extractor: for<'v> HasValidateArgs<'v> + FromRequest<State, Body>,
204
{
205
    type Rejection = ValidRejection<<Extractor as FromRequest<State, Body>>::Rejection>;
×
206

207
    async fn from_request(req: Request<Body>, state: &State) -> Result<Self, Self::Rejection> {
174✔
208
        let arguments: Args = FromRef::from_ref(state);
58✔
209
        let inner = Extractor::from_request(req, state)
145✔
210
            .await
58✔
211
            .map_err(ValidRejection::Inner)?;
29✔
212

213
        inner.get_validate_args().validate_args(arguments.get())?;
87✔
214
        Ok(ValidEx(inner, arguments))
29✔
215
    }
216
}
217

218
#[async_trait]
219
impl<State, Extractor, Args> FromRequestParts<State> for ValidEx<Extractor, Args>
×
220
where
221
    State: Send + Sync,
222
    Args: Send
223
        + Sync
224
        + FromRef<State>
225
        + for<'a> Arguments<'a, T = <Extractor as HasValidateArgs<'a>>::ValidateArgs>,
226
    Extractor: for<'v> HasValidateArgs<'v> + FromRequestParts<State>,
227
{
228
    type Rejection = ValidRejection<<Extractor as FromRequestParts<State>>::Rejection>;
229

230
    async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> {
130✔
231
        let arguments: Args = FromRef::from_ref(state);
26✔
232
        let inner = Extractor::from_request_parts(parts, state)
124✔
233
            .await
52✔
234
            .map_err(ValidRejection::Inner)?;
23✔
235
        inner.get_validate_args().validate_args(arguments.get())?;
78✔
236
        Ok(ValidEx(inner, arguments))
26✔
237
    }
238
}
239

240
#[cfg(test)]
241
pub mod tests {
242
    use super::*;
243
    use std::error::Error;
244
    use std::fmt::Formatter;
245
    use std::io;
246
    use validator::ValidationError;
247
    const TEST: &str = "test";
248

249
    #[test]
250
    fn valid_deref_deref_mut_into_inner() {
251
        let mut inner = String::from(TEST);
252
        let mut v = Valid(inner.clone());
253
        assert_eq!(&inner, v.deref());
254
        inner.push_str(TEST);
255
        v.deref_mut().push_str(TEST);
256
        assert_eq!(&inner, v.deref());
257
        println!("{}", v);
258
        assert_eq!(inner, v.into_inner());
259
    }
260

261
    #[test]
262
    fn valid_ex_deref_deref_mut_into_inner_arguments() {
263
        let mut inner = String::from(TEST);
264
        let mut v = ValidEx(inner.clone(), ());
265
        assert_eq!(&inner, v.deref());
266
        inner.push_str(TEST);
267
        v.deref_mut().push_str(TEST);
268
        assert_eq!(&inner, v.deref());
269
        assert_eq!(inner, v.into_inner());
270

271
        fn validate(_v: i32, _args: i32) -> Result<(), ValidationError> {
272
            Ok(())
273
        }
274

275
        #[derive(Debug, Validate)]
276
        struct Data {
277
            #[validate(custom(function = "validate", arg = "i32"))]
278
            v: i32,
279
        }
280

281
        impl Display for Data {
282
            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
283
                write!(f, "{:?}", self)
284
            }
285
        }
286

287
        struct DataVA {
288
            a: i32,
289
        }
290

291
        impl<'a> Arguments<'a> for DataVA {
292
            type T = Data;
293

294
            fn get(&'a self) -> <<Self as Arguments<'a>>::T as ValidateArgs<'a>>::Args {
295
                self.a
296
            }
297
        }
298

299
        let data = Data { v: 12 };
300
        let args = DataVA { a: 123 };
301
        let ve = ValidEx(data, args);
302
        println!("{}", ve);
303
        assert_eq!(ve.v, 12);
304
        let a = ve.arguments();
305
        assert_eq!(a, 123);
306
    }
307

308
    #[test]
309
    fn display_error() {
310
        // ValidRejection::Valid Display
311
        let mut ve = ValidationErrors::new();
312
        ve.add(TEST, ValidationError::new(TEST));
313
        let vr = ValidRejection::<String>::Valid(ve.clone());
314
        assert_eq!(vr.to_string(), ve.to_string());
315

316
        // ValidRejection::Inner Display
317
        let inner = String::from(TEST);
318
        let vr = ValidRejection::<String>::Inner(inner.clone());
319
        assert_eq!(inner.to_string(), vr.to_string());
320

321
        // ValidRejection::Valid Error
322
        let mut ve = ValidationErrors::new();
323
        ve.add(TEST, ValidationError::new(TEST));
324
        let vr = ValidRejection::<io::Error>::Valid(ve.clone());
325
        assert!(
326
            matches!(vr.source(), Some(source) if source.downcast_ref::<ValidationErrors>().is_some())
327
        );
328

329
        // ValidRejection::Valid Error
330
        let vr = ValidRejection::<io::Error>::Inner(io::Error::new(io::ErrorKind::Other, TEST));
331
        assert!(
332
            matches!(vr.source(), Some(source) if source.downcast_ref::<io::Error>().is_some())
333
        );
334
    }
335
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc