Data Validation in Rust: Overview of Libraries and Practical Approaches
In modern Rust development, especially when creating web services and APIs, validating incoming data is a critically important task. The Rust language already provides a powerful type system that eliminates entire classes of errors at compile time. However, additional tools are needed to check business logic (e.g., minimum password length, email correctness, number ranges). In this article, we will look at three of the most popular libraries for data validation in Rust: validator, garde, and valitron.
1. The validator Library
validator is arguably the most well-known and mature library for validating structs in Rust. It is built on attributes (derive macros) and supports many built-in rules.
Installation:
[dependencies]validator = { version = "0.18", features = ["derive"] }Usage Example:
use validator::Validate;
#[derive(Debug, Validate)]struct User { #[validate(length(min = 3, max = 20))] username: String,
#[validate(email)] email: String,
#[validate(range(min = 18, max = 120))] age: u32,
#[validate(required)] password: Option<String>,}
fn main() { let user = User { username: "Jo".to_string(), email: "invalid-email".to_string(), age: 15, password: None, };
match user.validate() { Ok(_) => println!("Validation passed!"), Err(errors) => { for (field, err) in &errors.errors() { println!("Error in field '{}': {:?}", field, err); } } }}Advantages:
- Large number of built-in validators: email, URL, length, range, regular expressions.
- Support for custom validation functions via the
customattribute. - Good integration with web frameworks (Actix-web, Axum, Rocket).
Disadvantages:
- Depends on macros, which can slow down compilation.
- Errors are returned as a
HashMap, requiring additional processing for APIs.
2. The garde Library
garde is a more modern and faster alternative to validator. It also uses derive macros but offers a more flexible API and better performance.
Installation:
[dependencies]garde = "0.20"Usage Example:
use garde::Validate;
#[derive(Debug, Validate)]struct LoginRequest { #[garde(length(min = 3, max = 50))] username: String,
#[garde(ascii, length(min = 8))] password: String,
#[garde(skip)] remember_me: bool,}
fn main() { let req = LoginRequest { username: "ab".to_string(), password: "1234567".to_string(), remember_me: true, };
if let Err(errors) = req.validate() { for error in &errors { println!("Error: {} - {}", error.path(), error.message()); } } else { println!("Validation successful!"); }}Advantages:
- High performance due to optimized code.
- Clear error messages with the field path.
- Support for nested structs and collections.
- Ability to create custom rules without macros.
Disadvantages:
- Fewer built-in validators (no email, URL by default).
- Smaller community compared to
validator.
3. The valitron Library
valitron is a lightweight library that does not use
Also in library
Working with Excel in Kotlin: Apache POI Libraries and Kotlin Wrappers
Working with Dates in Swift: Foundation, SwiftDate, DateTools (iOS/macOS)
Working with ZIP Archives in C# (.NET): A Complete Guide
Elasticsearch client for Kotlin: integration, examples, and capabilities
Go Application Configuration: Viper Library