Garde

A Rust validation library
- Basic usage example
- Validation rules
- Inner type validation
- Handling Option
- Custom validation
- Custom validation with containers
- Context/Self access
- Implementing rules
- Implementing
Validate - Integration with web frameworks
- Feature flags
- Why
garde?
Basic usage example
To get started, use the Validate derive macro and add some validation rules to your type.
This generates an implementation of the Validate trait for you.
To use it, call the validate method on an instance of the type.
Here's what that looks like in full:
use ;
let user = User ;
if let Err = user.validate
Garde can also validate enums:
use ;
let data = Struct ;
if let Err = data.validate
Available validation rules
| name | format | validation | feature flag |
|---|---|---|---|
| required | #[garde(required)] |
is value set | - |
| ascii | #[garde(ascii)] |
only contains ASCII | - |
| alphanumeric | #[garde(alphanumeric)] |
only letters and digits | - |
#[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 container with length in min..=max |
- |
| byte_length | #[garde(byte_length(min=<usize>, max=<usize>)] |
a byte sequence with length in 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 | regex |
| pattern | #[garde(pattern(<matcher>))] |
a string-like value matched by some Matcher | - |
| dive | #[garde(dive)] |
nested validation, calls validate on the value |
- |
| skip | #[garde(skip)] |
skip validation | - |
| custom | #[garde(custom(<function or closure>))] |
a custom validator | - |
Additional notes:
requiredis only available forOptionfields.- For
lengthandrange, eitherminormaxmay be omitted, but not both. lengthandrangeuse an inclusive upper bound (min..=max).lengthuses.chars().count()for UTF-8 strings instead of.len().- For
contains,prefix, andsuffix, the pattern must be a string literal, because thePatternAPI is currently unstable. - Garde does not enable the default features of the
regexcrate - if you need extra regex features (e.g. Unicode) or better performance, add a dependency onregex = "1"to yourCargo.toml.
If most of the fields on your struct are annotated with #[garde(skip)], you may use #[garde(allow_unvalidated)] instead:
Inner type validation
If you need to validate the "inner" type of a container, such as the String in Vec<String>, then use the inner modifier:
The above type would fail validation if:
- the
Vecis empty - any of the inner
Stringelements is empty - any of the inner
Stringelements contains non-ASCII characters
Handling Option
Every rule works on Option<T> fields. The field will only be validated if it is Some. If you additionally want to validate that the Option<T> field is Some, use the required rule:
The above type would fail validation if:
valueisNone- the inner
valueis empty - the inner
valuecontains non-ASCII characters
Custom validation
Validation may be customized via the custom rule, and the context attribute.
The context may be any type without generic parameters. By default, the context is ().
let ctx = PasswordContext ;
let user = User ;
user.validate?;
The validator function may accept the value as a reference to any type which it derefs to.
In the above example, it is possible to use &str, because password is a String, and String derefs to &str.
Custom validation with containers
When working with custom validators, if the type is a container such as Vec<T> or Option<T>, the validation function will get a reference to that container instead of the underlying data. This is in contrast with built-in validators that are able to extract the type from some container types such as Option<T>.
To validate the underlying data of a container when using a custom validator, use the inner modifier:
let ctx = PasswordContext ;
let user = User ;
user.validate?;
The above type will always pass validation if the password field is None.
This allows you to use the same validation function for T as you do for Option<T> or Vec<T>.
Context/Self access
It's generally possible to also access the context and self, because they are in scope in the output of the proc macro:
Implementing rules
Say you want to implement length checking for a custom string-like type.
To do this, you would implement the garde::rules::length::HasLength trait for it.
;
Each rule comes with its own trait that may be implemented by custom types in your code.
They are all available under garde::rules.
Implementing Validate
In case you have a container type for which you'd like to support nested validation (using the #[garde(dive)] rule),
you may implement Validate for it:
;
Integration with web frameworks
Feature flags
| 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 |
regex |
Support for regular expressions in pattern 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 |
Why 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 :).
Development
Contributing to garde only requires a somewhat recent version of Rust.
This repository also makes use of the following tools, but they are optional:
instafor snapshot testing (tests/rules).justfor running recipes defined in thejustfile. Runjust -lto see what recipes are available.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
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.
Acknowledgements
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.