Валидация данных в Rust: библиотеки и подходы

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Валидация данных в Rust: обзор библиотек и практических подходов

В современной разработке на Rust, особенно при создании веб-сервисов и API, валидация входящих данных — критически важная задача. Язык Rust уже предоставляет мощную систему типов, которая отсекает целые классы ошибок на этапе компиляции. Однако для проверки бизнес-логики (например, минимальная длина пароля, корректность email, диапазон чисел) нужны дополнительные инструменты. В этой статье мы рассмотрим три наиболее популярные библиотеки для валидации данных в Rust: validator, garde и valitron.

1. Библиотека validator

validator — это, пожалуй, самая известная и зрелая библиотека для валидации структур в Rust. Она построена на атрибутах (derive macros) и поддерживает множество встроенных правил.

Установка:

[dependencies]
validator = { version = "0.18", features = ["derive"] }

Пример использования:

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!("Валидация пройдена!"),
        Err(errors) => {
            for (field, err) in &errors.errors() {
                println!("Ошибка в поле '{}': {:?}", field, err);
            }
        }
    }
}

Преимущества:

  • Большое количество встроенных валидаторов: email, URL, длина, диапазон, регулярные выражения.
  • Поддержка кастомных функций валидации через атрибут custom.
  • Хорошая интеграция с веб-фреймворками (Actix-web, Axum, Rocket).

Недостатки:

  • Зависит от макросов, что может замедлить компиляцию.
  • Ошибки возвращаются в виде HashMap, что требует дополнительной обработки для API.

2. Библиотека garde

garde — более современная и быстрая альтернатива validator. Она также использует derive-макросы, но предлагает более гибкий API и лучшую производительность.

Установка:

[dependencies]
garde = "0.20"

Пример использования:

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.path(), error.message());
        }
    } else {
        println!("Валидация успешна!");
    }
}

Преимущества:

  • Высокая производительность за счёт оптимизированного кода.
  • Чёткие сообщения об ошибках с путём к полю.
  • Поддержка вложенных структур и коллекций.
  • Возможность создавать свои правила без макросов.

Недостатки:

  • Меньше встроенных валидаторов (нет email, URL по умолчанию).
  • Сообщество меньше, чем у validator.

3. Библиотека valitron

valitron — это лёгкая библиотека, которая не использует макросы. Вместо этого она предлагает fluent-интерфейс для построения правил валидации. Это может быть удобно, когда структура данных динамическая или неизвестна на этапе компиляции.

Установка:

[dependencies]
valitron = "0.5"

Пример использования:

use valitron::{Validator, Rule};

fn main() {
    let data = serde_json::json!({
        "name": "A",
        "email": "bad",
        "age": 17
    });

    let validator = Validator::new()
        .rule("name", Rule::required().length(3..=50))
        .rule("email", Rule::required().email())                    

Рекомендаций