28个版本 (17个重大更改)
0.18.1 | 2024年4月11日 |
---|---|
0.17.0 | 2024年3月4日 |
0.16.0 | 2022年7月25日 |
0.14.0 | 2021年6月29日 |
0.1.0 | 2016年12月28日 |
#538 in 过程宏
728,440 每月下载量
用于 257 个库 (16个直接使用)
55KB
1K SLoC
validator
受 marshmallow 和 Django 验证器启发的结构验证宏 1.1 实现以简化宏 derive
最低支持版本是 Rust 1.42。
安装
[dependencies]
validator = { version = "0.16", 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(url)]
site: String,
#[validate(length(min = 1), custom(function = "validate_unique_username"))]
#[serde(rename = "firstName")]
first_name: String,
#[validate(range(min = 18, max = 20))]
age: u32,
#[validate(range(exclusive_min = 0.0, max = 100.0))]
height: f32,
}
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
。该字段的任何错误都将出现在 hashmap 的 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,
}
#[derive(Debug, Validate, Deserialize)]
struct Preference {
#[validate(length(min = 4))]
name: String,
value: bool,
}
match signup_data.validate() {
Ok(_) => (),
Err(e) => return e;
};
在这里,ContactDetails
和 Preference
结构体嵌套在父 SignupData
结构体中。因为这些子类型也派生了 Validate
,所以它们出现的字段可以被标记为包含在父结构体的验证方法中。
在单个嵌套结构体(本例中的 contact_details
字段)中发现的任何错误都将作为父结构体 ValidationErrors
结果中的 Struct(Box<ValidationErrors>)
类型返回。
在嵌套结构体向量(本例中的 preferences
字段)中发现的任何错误将作为父结构体 ValidationErrors
结果中的 List(BTreeMap<usize, Box<ValidationErrors>>)
类型返回,其中映射是根据无效向量条目的索引键的。
用法
您需要导入 Validate
特性。
validator
包也可以在不使用自定义派生的前提下使用,因为它公开了所有验证函数和类型。
验证器
该包包含一些内置验证器,并且可以为给定字段有多个验证器。
测试字符串是否是有效的电子邮件地址,根据 HTML5 正则表达式,这意味着它将标记一些古怪电子邮件地址为无效,这些地址在 email
输入中也是无效的。此验证器不接受任何参数:#[validate(email)]
。
url
测试字符串是否是有效的 URL。此验证器不接受任何参数:#[validate(url)]
;
length
测试字符串或 Vec 是否匹配给定的长度要求。 length
有 3 个整数参数
- min
- max
- equal
使用 equal
排除了 min
或 max
,如果在它们中发现这些参数,将导致编译错误。
需要至少一个参数,最多两个参数(同时具有 min
和 max
)。
示例
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 个参数,它们可以是普通(min
和 max
)或排他性(exclusive_min
、exclusive_max
、不可达限制)。这些可以是数字或值路径。
示例
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"))]
#[validate(range(exclusive_min = 0.0, max = 100.0))]
#[validate(range(exclusive_max = 10))]
must_match
测试两个字段是否相等。 must_match
需要 1 个字符串参数。如果提到的字段缺失或与属性所在的字段类型不同,则将引发错误。
示例
#[validate(must_match = "password2")]
#[validate(must_match(other = "password2"))]
contains
测试字符串是否包含给定的子字符串,或者键是否存在于哈希映射中。 contains
需要 1 个字符串参数。
示例
#[validate(contains = "gmail")]
#[validate(contains(pattern = "gmail"))]
does_not_contain
几乎与contains相反,仅为了方便使用。测试容器是否不包含给定的子字符串,如果是字符串,或者在一个哈希表中键是否不存在。does_not_contain
需要一个字符串参数。
示例
#[validate(does_not_contain = "gmail")]
#[validate(does_not_contain(pattern = "gmail"))]
正则表达式
测试字符串是否与给定的正则表达式匹配。regex
需要一个字符串参数:静态正则表达式实例的路径。
示例
use once_cell::sync::Lazy;
static RE_TWO_CHARS: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"[a-z]{2}$").unwrap()
});
#[validate(regex = "RE_TWO_CHARS")]
#[validate(regex(path = "RE_TWO_CHARS"))]
信用卡
测试字符串是否为有效的信用卡号码。
示例
#[validate(credit_card)]
自定义
调用您的函数之一以执行自定义验证。字段引用将作为参数传递给函数,该函数应返回一个Result<(), ValidationError>
。
示例
#[validate(custom(function = "validate_something"))]
#[validate(custom(function = "::utils::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.rs
和validator_derive_tests/tests/custom_args.rs
以获取更多示例。
嵌套
对实现Validate特质(或这些类型的向量)的类型字段执行验证。
示例
#[validate]
非控制字符
测试字符串是否包含任何utf-8控制字符,如果包含则验证失败。要使用此验证器,您必须为validator
包启用unic
功能。此验证器不接收任何参数:#[validate(non_control_character)]
;
必需的
测试Option<T>
字段是否为Some
;
结构级验证
通常,某些错误验证只能在查看整个结构时应用,这里是如何实现的
#[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__
中。
消息和代码
每个验证器除了自己的参数外,还可以接受两个可选参数
message
:一个与错误相关的消息,例如,如果您想进行i18ncode
:每个验证器都有一个默认的错误代码(例如,正则表达式验证器的代码是regex
),但在必要时可以覆盖,主要需要自定义验证器
请注意,这些参数不能应用于嵌套的带有 #[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"))]
依赖项
~0.7–1.1MB
~25K SLoC