Expand description
A Rust validation library
- Basic usage example
- Validation rules
- Custom validation
- Implementing rules
- Implementing
Validate - 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 garde::{Validate, Valid};
#[derive(Validate)]
struct User<'a> {
#[garde(ascii, length(min=3, max=25))]
username: &'a str,
#[garde(length(min=15))]
password: &'a str,
}
let user = User {
username: "test",
password: "not_a_very_good_password",
};
if let Err(e) = user.validate(&()) {
println!("invalid user: {e}");
}Garde can also validate enums:
use garde::{Validate, Valid};
#[derive(Validate)]
enum Data {
Struct {
#[garde(range(min=-10, max=10))]
field: i32,
},
Tuple(
#[garde(ascii)]
String
),
}
let data = Data::Struct { field: 100 };
if let Err(e) = data.validate(&()) {
println!("invalid data: {e}");
}Available validation rules
| name | format | validation | feature flag |
|---|---|---|---|
| ascii | #[garde(ascii)] | only contains ASCII | - |
| alphanumeric | #[garde(alphanumeric)] | only letters and digits | - |
#[garde(email)] | an email according to the HTML5 spec1 | 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 | - |
| skip | #[garde(skip)] | skip validation | - |
| custom | #[garde(custom(<function or closure>))] | a custom validator | - |
Additional notes:
- 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. - Nested validation using
divemay not be combined with any other rule.
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 ().
#[derive(garde::Validate)]
#[garde(context(PasswordContext))]
struct User {
#[garde(custom(is_strong_password))]
password: String,
}
struct PasswordContext {
min_entropy: f32,
entropy: cracken::password_entropy::EntropyEstimator,
}
fn is_strong_password(value: &str, context: &PasswordContext) -> garde::Result {
let bits = context.entropy.estimate_password_entropy(value.as_bytes())
.map(|e| e.mask_entropy)
.unwrap_or(0.0);
if bits < context.min_entropy {
return Err(garde::Error::new("password is not strong enough"));
}
Ok(())
}
let ctx = PasswordContext { /* ... */ };
let user = User { /* ... */ };
user.validate(&ctx)?;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.
Implementing rules
Say you want to implement length checking for a custom string-like type.
To do this, you would implement the rules::length::HasLength trait for it.
#[repr(transparent)]
pub struct MyString(pub String);
impl garde::rules::length::HasLength for MyString {
fn length(&self) -> usize {
self.0.chars().count()
}
}
#[derive(garde::Validate)]
struct Foo {
// Now the `length` check may be used with `MyString`
#[garde(length(min = 1, max = 1000))]
field: MyString,
}Each rule comes with its own trait that may be implemented by custom types in your code.
They are all available under 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 manually implement Validate for it:
#[repr(transparent)]
struct MyVec<T>(Vec<T>);
impl<T: garde::Validate> garde::Validate for MyVec<T> {
type Context = T::Context;
fn validate(&self, ctx: &Self::Context) -> Result<(), garde::Errors> {
garde::Errors::list(|errors| {
for item in self.0.iter() {
errors.push(item.validate(ctx));
}
})
.finish()
}
}
#[derive(garde::Validate)]
struct Foo {
#[garde(dive)]
field: MyVec<Bar>,
}
#[derive(garde::Validate)]
struct Bar {
#[garde(range(min = 1, max = 10))]
value: u32,
}To make implementing the trait easier, the error::Errors type supports a nesting builders.
- For list-like or tuple-like data structures, use
Errors::list, and its.pushmethod to attach nestedErrors. - For map-like data structures, use
Errors::fields, and its.insertmethod to attach nestedErrors. - For a “flat” error list, use
Errors::simple, and its.pushmethod to attach individual errors.
The ListErrorBuilder::push and ListErrorBuilder::insert methods will ignore any errors which are empty (via Errors::is_empty).
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 |
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. | - |
Re-exports
pub use error::Error;pub use error::Errors;pub use validate::Unvalidated;pub use validate::Valid;pub use validate::Validate;