A Rust validation library
```rust use garde::{Validate, Valid}; use serde::Deserialize;
struct User<'a> { #[garde(ascii, length(min=3, max=25))] username: &'a str, #[garde(length(min=15))] password: &'a str, }
let user = serdejson::fromstr::
println!("{}", user.validate(&()).unwrap_err()); ```
Garde can also validate enums:
```rust use garde::{Validate, Valid}; use serde::Deserialize;
enum Data { Struct { #[garde(range(min=-10, max=10))] field: i32, }, Tuple( #[garde(rename="important", ascii)] String ), }
let data = serdejson::fromstr::
for item in &data { println!("{}", item.validate(&()).unwrap_err()); } ```
| name | format | validation | feature flag |
|--------------|---------------------------------------------|--------------------------------------------------------------|----------------|
| ascii | #[garde(ascii)]
| only contains ASCII | - |
| alphanumeric | #[garde(alphanumeric)]
| only letters and digits | - |
| email | #[garde(email)]
| an email according to the HTML5 spec[^1] | email
|
| url | #[garde(url)]
| a URL | url
|
| ip | #[garde(ip)]
| an IP address (either IPv4 or IPv6) | - |
| ipv4 | #[garde(ipv4)]
| an IPv4 address | - |
| ipv6 | #[garde(ipv6)]
| an IPv6 address | - |
| credit card | #[garde(credit_card)]
| a credit card number | credit-card
|
| phone number | #[garde(phone_number)]
| a phone number | phone-number
|
| length | #[garde(length(min=<usize>, max=<usize>)]
| a dynamically-sized value with size in the range min..=max
| - |
| range | #[garde(range(min=<expr>, max=<expr>))]
| a number in the range min..=max
| - |
| contains | #[garde(contains(<string>))]
| a string-like value containing a substring | - |
| prefix | #[garde(prefix(<string>))]
| a string-like value prefixed by some string | - |
| suffix | #[garde(suffix(<string>))]
| a string-like value suffixed by some string | - |
| pattern | #[garde(pattern(<regex>))]
| a string-like value matching some regular expression | pattern
|
| dive | #[garde(dive)]
| nested validation, calls validate
on the value | - |
| custom | #[garde(custom(<function or closure>))]
| a custom validator | - |
Additional notes:
- For length
and range
, either min
or max
may be omitted, but not both.
- length
and range
use an inclusive upper bound (min..=max
).
- length
uses .chars().count()
for UTF-8 strings instead of .len()
.
- For contains
, prefix
, and suffix
, the pattern must be a string literal, because the Pattern
API is currently unstable.
- Nested validation using dive
may not be combined with any other rule.
| name | description | extra dependencies |
|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|
| derive
| Enables the usage of the derive(Validate)
macro | garde_derive
|
| url
| Validation of URLs via the url
crate. | url
|
| email
| Validation of emails according to HTML5 | regex
, once_cell
|
| email-idna
| Support for Internationalizing Domain Names for Applications in email addresses | idna
|
| pattern
| Validation using regular expressions via the regex
crate | regex
, once_cell
|
| credit-card
| Validation of credit card numbers via the card-validate
crate | card-validate
|
| phone-number
| Validation of phone numbers via the phonenumber
crate | phonenumber
|
| nightly-error-messages
| Enables usage of rustc_on_unimplemented
for better error messages. This is an unstable feature and requires a nightly compiler. | - |
Garde
?Garde means guard in French. I am not French, nor do I speak the language, but guard
was taken, and this is close enough :).
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
This crate is heavily inspired by the validator crate. It is essentially a full rewrite of validator
.
The creation of this crate was prompted by this comment
and a few others talking about a potential rewrite.