#validation #macro #macro-derive #api #field #struct #struct-fields

validator_types

validator和validator_derive的基本类型

5个版本 (重大变更)

0.16.0 2022年7月25日
0.15.0 2022年5月3日
0.14.0 2021年6月29日
0.12.0 2020年11月26日
0.11.0 2020年9月9日

Rust模式中排名1656

Download history 125941/week @ 2024-04-20 130015/week @ 2024-04-27 123285/week @ 2024-05-04 146114/week @ 2024-05-11 145482/week @ 2024-05-18 141675/week @ 2024-05-25 166029/week @ 2024-06-01 150798/week @ 2024-06-08 140670/week @ 2024-06-15 150132/week @ 2024-06-22 137670/week @ 2024-06-29 145802/week @ 2024-07-06 152474/week @ 2024-07-13 156577/week @ 2024-07-20 143813/week @ 2024-07-27 139683/week @ 2024-08-03

每月下载量616,443

MIT许可证

6KB
88

validator

Build

Macros 1.1自定义 derive 用于简化结构体验证,灵感来源于marshmallowDjango验证器

最低支持的 Rust 版本是 1.42。

安装

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

一个简短的例子

use serde::Deserialize;

// A trait that the Validate derive will impl
use validator::{Validate, ValidationError};

#[derive(Debug, Validate, Deserialize)]
struct SignupData {
    #[validate(email)]
    mail: String,
    #[validate(phone)]
    phone: String,
    #[validate(url)]
    site: String,
    #[validate(length(min = 1), custom = "validate_unique_username")]
    #[serde(rename = "firstName")]
    first_name: String,
    #[validate(range(min = 18, max = 20))]
    age: u32,
}

fn validate_unique_username(username: &str) -> Result<(), ValidationError> {
    if username == "xXxShad0wxXx" {
        // the value of the username will automatically be added later
        return Err(ValidationError::new("terrible_username"));
    }

    Ok(())
}

match signup_data.validate() {
  Ok(_) => (),
  Err(e) => return e;
};

对一个Option<_>字段的验证将在该选项为Some时对其包含的类型执行。该validate()方法返回一个Result<(), ValidationErrors>。在无效结果的情况下,ValidationErrors实例包含一个以结构体的字段名为键的映射。错误可以用三种方式表示,如ValidationErrorsKind枚举所述

#[derive(Debug, Serialize, Clone, PartialEq)]
#[serde(untagged)]
pub enum ValidationErrorsKind {
    Struct(Box<ValidationErrors>),
    List(BTreeMap<usize, Box<ValidationErrors>>),
    Field(Vec<ValidationError>),
}

在上面的简单示例中,任何错误都会是Field(Vec<ValidationError>)类型,其中单个ValidationError具有以下结构

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct ValidationError {
  pub code: Cow<'static, str>,
  pub message: Option<Cow<'static, str>>,
  pub params: HashMap<Cow<'static, str>, Value>,
}

字段的值将自动添加到键为value的参数中。

注意,validator与serde一起使用:在示例中,我们可以看到first_name字段被重命名为firstName。该字段的任何错误都将出现在哈希表的firstName键中,而不是first_name键中。

其他两个ValidationErrorsKind类型表示在嵌套(结构体的向量)中发现的错误,如本示例所述

use serde::Deserialize;
// A trait that the Validate derive will impl
use validator::Validate;

#[derive(Debug, Validate, Deserialize)]
struct SignupData {
   #[validate]
   contact_details: ContactDetails,
   #[validate]
   preferences: Vec<Preference>,
   #[validate(required)]
   allow_cookies: Option<bool>,
}

#[derive(Debug, Validate, Deserialize)]
struct ContactDetails {
   #[validate(email)]
   mail: String,
   #[validate(phone)]
   phone: String
}

#[derive(Debug, Validate, Deserialize)]
struct Preference {
   #[validate(length(min = 4))]
   name: String,
   value: bool,
}

match signup_data.validate() {
 Ok(_) => (),
 Err(e) => return e;
};

在这里,ContactDetailsPreference 结构体嵌套在父 SignupData 结构体内部。因为这些子类型也派生了 Validate,所以它们出现的字段可以被标记为包含在父结构体的验证方法中。

在单个嵌套结构体(本例中的 contact_details 字段)中找到的任何错误都会作为父结构体的 ValidationErrors 结果中的 Struct(Box<ValidationErrors>>) 类型返回。

在嵌套结构体数组(本例中的 preferences 字段)中找到的任何错误都会作为父结构体的 ValidationErrors 结果中的 List(BTreeMap<usize, Box<ValidationErrors>>) 类型返回,其中映射是以无效向量条目的索引为键。

使用方法

您需要导入 Validate 特性。

validator 插件也可以不使用自定义派生使用,因为它公开了所有验证函数和类型。

验证器

插件附带了一些内置验证器,并且可以为特定字段拥有多个验证器。

email

测试字符串是否为有效的电子邮件地址,根据 HTML5 正则表达式,这意味着它将一些古怪的电子邮件标记为无效,这些电子邮件在 email 输入中也不有效。此验证器不接收任何参数:#[validate(email)]

url

测试字符串是否为有效的 URL。此验证器不接收任何参数:#[validate(url)];

length

测试字符串或 Vec 是否符合给定的长度要求。 length 有 3 个整数参数

  • min
  • max
  • equal

使用 equal 排除 minmax,如果它们被发现,将会导致编译错误。

至少需要一个参数,最多可以有 2 个(同时拥有 minmax)。

示例

const MIN_CONST: u64 = 1;
const MAX_CONST: u64 = 10;

#[validate(length(min = 1, max = 10))]
#[validate(length(min = 1))]
#[validate(length(max = 10))]
#[validate(length(equal = 10))]
#[validate(length(min = "MIN_CONST", max = "MAX_CONST"))]

range

测试数字是否在给定范围内。 range 需要 1 或 2 个参数 minmax,可以是数字或值路径。

示例

const MAX_CONSTANT: i32 = 10;
const MIN_CONSTANT: i32 = 0;

#[validate(range(min = 1))]
#[validate(range(min = "MIN_CONSTANT"))]
#[validate(range(min = 1, max = 10))]
#[validate(range(min = 1.1, max = 10.8))]
#[validate(range(max = 10.8))]
#[validate(range(min = "MAX_CONSTANT"))]
#[validate(range(min = "crate::MAX_CONSTANT"))]

must_match

测试两个字段是否相等。 must_match 需要 1 个字符串参数。如果提到的字段缺失或与属性所在的字段类型不同,将引发错误。

示例

#[validate(must_match = "password2")]
#[validate(must_match(other = "password2"))]

contains

测试字符串是否包含给定的子字符串或 hashmap 中是否存在键。 contains 需要 1 个字符串参数。

示例

#[validate(contains = "gmail")]
#[validate(contains(pattern = "gmail"))]

does_not_contain

基本上与 contains 相反,仅为了方便使用。测试容器是否不包含给定的子字符串(如果它是字符串)或在 hashmap 中不存在键。 does_not_contain 需要 1 个字符串参数。

示例

#[validate(does_not_contain = "gmail")]
#[validate(does_not_contain(pattern = "gmail"))]

regex

检测字符串是否与提供的正则表达式匹配。regex 接受 1 个字符串参数:静态 Regex 实例的路径。

示例

lazy_static! {
    static ref RE_TWO_CHARS: Regex = Regex::new(r"[a-z]{2}$").unwrap();
}

#[validate(regex = "RE_TWO_CHARS")]
#[validate(regex(path = "RE_TWO_CHARS"))]

credit_card

测试字符串是否是有效的信用卡号码。

示例

#[validate(credit_card)]

phone

测试字符串是否是有效的电话号码(国际格式,即包含国家代码,如 +14152370800 表示美国号码 —— 其中 4152370800 是国家号码等效,被视为无效)。要使用此验证器,您必须为 validator 包启用 phone 功能。此验证器不接受任何参数:#[validate(phone)];

custom

调用您的其中一个函数以执行自定义验证。字段引用将作为参数传递给函数,该函数应返回一个 Result<(), ValidationError>

示例

#[validate(custom = "validate_something")]
#[validate(custom = "::utils::validate_something")]
#[validate(custom(function = "validate_something"))]

您还可以通过设置 arg 参数,从验证函数解析参数到您的自定义验证。arg 只能设置为一种类型,但您可以将其设置为元组以一次传递多个类型。定义 arg 参数将实现 ValidateArgs 特性以及对应的函数类型,如下所示

use validator::{Validate, ValidateArgs, ValidationError};

fn validate(value: &str, arg: (i64, i64)) -> Result<(), ValidationError> {
    [...]
}

#[derive(Debug, Validate)]
struct TestStruct {
    #[validate(custom(function = "validate", arg = "(i64, i64)"))]
    value: String,
}

let test_struct: TestStruct = [...]
test_struct.validate_args((77, 555)).is_ok();

您还可以使用生存期 'v_a 通过引用传递参数,注意这个生存期仅用于函数参数,如下所示

fn validate_value(_: &str, arg: &mut Database) -> Result<(), ValidationError> {
    [...]
}

#[derive(Debug, Validate)]
struct TestStruct {
    //                                                     vvvv This is the lifetime for references
    #[validate(custom(function = "validate_value", arg = "&'v_a mut Database"))]
    value: String,
}

let mut database: Database = [...]
let test_struct: TestStruct = [...]
test_struct.validate_args(&mut database).is_ok();

带有参数的自定义验证不支持嵌套验证。请参阅 validator_derive_tests/tests/custom.rsvalidator_derive_tests/tests/custom_args.rs 了解更多示例。

nested

对实现 Validate 特性(或此类类型的向量)的类型字段执行验证。

示例

#[validate]

non_control_character

测试字符串是否包含任何 utf-8 控制字符,如果有则验证失败。要使用此验证器,您必须为 validator 包启用 unic 功能。此验证器不接受任何参数:#[validate(non_control_character)];

required

测试 Option<T> 字段是否为 Some;

required_nested

测试 Option<T> 字段是否为 Some 并执行与 nested 一样的验证;

结构体级别验证

通常,一些错误验证只能在查看整个结构体时应用,这里是如何实现的。

#[derive(Debug, Validate, Deserialize)]
#[validate(schema(function = "validate_category", skip_on_field_errors = false))]
struct CategoryData {
    category: String,
    name: String,
}

所提到的函数应返回一个 Result<(), ValidationError>,并在对所有字段进行验证后调用。

如果没有指定,skip_on_field_errors 默认为 true,这将确保在验证结构体字段时发生错误时不会调用该函数。

结构体级别验证中的任何错误都将出现在错误哈希表的关键字 __all__ 中。

消息和代码

除了它们自己的参数外,每个验证器还可以接受2个可选参数

  • message:与错误相关的消息,例如如果您想进行国际化(i18n)
  • code:每个验证器都有一个默认的错误代码(例如,正则表达式验证器的代码是 regex),但必要时可以覆盖,主要用于 custom 验证器

请注意,这些参数不能应用于带有 #[validate] 的嵌套验证调用。

例如,以下属性都有效

// code attribute
#[validate(email(code = "code_str"))]
#[validate(credit_card(code = "code_str"))]
#[validate(length(min = 5, max = 10, code = "code_str"))]

#[validate(regex(path = "static_regex", code = "code_str"))]
#[validate(custom(function = "custom_fn", code = "code_str"))]
#[validate(contains(pattern = "pattern_str", code = "code_str"))]
#[validate(does_not_contain(pattern = "pattern_str", code = "code_str"))]
#[validate(must_match(other = "match_value", code = "code_str"))]

// message attribute
#[validate(url(message = "message_str"))]
#[validate(length(min = 5, max = 10, message = "message_str"))]

#[validate(regex(path = "static_regex", message = "message_str"))]
#[validate(custom(function = "custom_fn", message = "message_str"))]
#[validate(contains(pattern = "pattern_str", message = "message_str"))]
#[validate(does_not_contain(pattern = "pattern_str", message = "message_str"))]
#[validate(must_match(other = "match_value", message = "message_str"))]

// both attributes
#[validate(url(message = "message", code = "code_str"))]
#[validate(email(code = "code_str", message = "message"))]
#[validate(custom(function = "custom_fn", code = "code_str", message = "message_str"))]

依赖关系

~1.5MB
~35K SLoC