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

gengteng / axum-valid / 7020504044

28 Nov 2023 02:50PM UTC coverage: 89.903% (+0.2%) from 89.664%
7020504044

push

github

gengteng
build(deps): update axum requirement from 0.6.x to 0.7.x

82 of 85 new or added lines in 6 files covered. (96.47%)

12 existing lines in 5 files now uncovered.

1211 of 1347 relevant lines covered (89.9%)

11.82 hits per line

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

72.41
/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, Request};
14
use axum::http::request::Parts;
15
use std::fmt::Display;
16
use std::ops::{Deref, DerefMut};
17
use validator::{Validate, ValidateArgs, ValidationErrors};
18

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

165
    async fn from_request(req: Request, state: &State) -> Result<Self, Self::Rejection> {
84✔
166
        let inner = Extractor::from_request(req, state)
70✔
167
            .await
28✔
168
            .map_err(ValidRejection::Inner)?;
14✔
169
        inner.get_validate().validate()?;
42✔
170
        Ok(Valid(inner))
14✔
171
    }
172
}
173

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

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

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

204
    async fn from_request(req: Request, state: &State) -> Result<Self, Self::Rejection> {
84✔
205
        let arguments: Args = FromRef::from_ref(state);
28✔
206
        let inner = Extractor::from_request(req, state)
70✔
207
            .await
28✔
208
            .map_err(ValidRejection::Inner)?;
14✔
209

210
        inner.get_validate_args().validate_args(arguments.get())?;
42✔
211
        Ok(ValidEx(inner, arguments))
14✔
212
    }
213
}
214

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

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

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

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

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

268
        fn validate(_v: i32, _args: i32) -> Result<(), ValidationError> {
269
            Ok(())
270
        }
271

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

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

284
        struct DataVA {
285
            a: i32,
286
        }
287

288
        impl<'a> Arguments<'a> for DataVA {
289
            type T = Data;
290

291
            fn get(&'a self) -> <<Self as Arguments<'a>>::T as ValidateArgs<'a>>::Args {
292
                self.a
293
            }
294
        }
295

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

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

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

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

326
        // ValidRejection::Valid Error
327
        let vr = ValidRejection::<io::Error>::Inner(io::Error::new(io::ErrorKind::Other, TEST));
328
        assert!(
329
            matches!(vr.source(), Some(source) if source.downcast_ref::<io::Error>().is_some())
330
        );
331
    }
332
}
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