garde_actix_web/
lib.rs

1//! Actix-web wrapper for [garde](https://github.com/jprochazk/garde), a Rust validation library.
2//!
3//! # Installation
4//!
5//! ```toml
6//! [dependencies]
7//! garde = "0.22"
8//! garde-actix-web = "0.12"
9//! ```
10//!
11//! # Usage example
12//!
13//! Simply use `garde-actix-web` exposed types as a drop in for actix types.
14//!
15//! Your types must implement `Validate` from `garde`. Validation happens during actix's `FromRequest` invocation.
16//!
17//! If the payload is invalid, a 400 error is returned (404 for Path).
18//!
19//! Custom error handling can be implemented with an extractor config (`garde_actix_web::web::QueryConfig` in place of `actix_web::web::QueryConfig` for example).
20//!
21//! ```rust
22//! use actix_web::HttpResponse;
23//! // instead of actix_web::web::Path
24//! use garde_actix_web::web::Path;
25//! use garde::Validate;
26//!
27//! #[derive(Validate)]
28//! struct MyStruct<'a> {
29//!   #[garde(ascii, length(min=3, max=25))]
30//!   username: &'a str,
31//! }
32//!
33//! fn test(id: Path<MyStruct>) -> HttpResponse {
34//!   todo!()
35//! }
36//! ```
37//!
38//! ⚠️ When using `garde` [custom validation](https://github.com/jprochazk/garde#custom-validation), the `Context` type needs to implement `Default` which is not required by `garde`.
39//!
40//! # Feature flags
41//!
42//! | name       | description                                                   | extra dependencies                                                                           |
43//! |------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------|
44//! | `serde_qs` | Enables the usage of `garde` for `serde_qs::actix::QsQuery<T>` | [`serde_qs`](https://crates.io/crates/serde_qs)                                      |
45//!
46//! # Compatibility matrix
47//!
48//! | garde version | serde_qs version | garde-actix-web-version |
49//! |---------------|------------------|-------------------------|
50//! | `0.14`        | `0.12`           | `0.1.x`                 |
51//! | `0.15`        | `0.12`           | `0.2.x`                 |
52//! | `0.16`        | `0.12`           | `0.3.x`                 |
53//! | `0.17`        | `0.12`           | `0.4.x`                 |
54//! | `0.18`        | `0.12`           | `0.5.x`, `0.6.x`        |
55//! | `0.18`        | `0.13`           | `0.7.x`                 |
56//! | `0.19`        | `0.13`           | `0.8.x`                 |
57//! | `0.20`        | `0.13`           | `0.9.x`                 |
58//! | `0.20`        | `0.13`           | `0.10.x`                |
59//! | `0.22`        | `0.13`           | `0.11.x`                |
60//! | `0.22`        | `0.15`           | `0.12.x`                |
61
62#![forbid(unsafe_code)]
63
64use actix_web::HttpRequest;
65use actix_web::web::Data;
66use garde::Validate;
67
68pub mod error;
69pub mod web;
70
71fn validate_for_request<T>(data: T, req: &HttpRequest) -> Result<T, error::Error>
72where
73  T: Validate + 'static,
74  T::Context: Default,
75{
76  let context = req
77    .app_data::<T::Context>()
78    .or_else(|| req.app_data::<Data<T::Context>>().map(|d| d.as_ref()));
79
80  match context {
81    None => data.validate().map(|_| data).map_err(Into::into),
82    Some(ctx) => data.validate_with(ctx).map(|_| data).map_err(Into::into),
83  }
84}