52 个版本 (19 个稳定版)
4.0.0 | 2023 年 5 月 13 日 |
---|---|
4.0.0-rc.0 | 2023 年 2 月 20 日 |
3.6.1 | 2022 年 8 月 10 日 |
3.6.0 | 2021 年 2 月 20 日 |
0.1.0 | 2014 年 11 月 23 日 |
#78 在 Rust 模式
401,037 次每月下载
在 38 个crate中使用 (29 个直接使用)
290KB
8K SLoC
什么是 Valico?
Valico 是一个用于 JSON 对象的验证和转换工具,用 Rust 编写。它旨在作为各种类似 REST 的框架或其他需要从外部世界验证和转换 JSON 输入的工具的支持库。
Valico 有两个功能
- DSL — 一组简单的验证器和转换器,灵感来自 [Grape]。它内置了对常见转换器、验证器的支持,并在出错时可以返回详细的错误信息。
- JSON Schema — 基于 IETF 草案 v7 的 JSON Schema 实现。
参考资料
- https://json-schema.fullstack.org.cn
- https://json-schema.fullstack.org.cn/latest/json-schema-core.html
- https://json-schema.fullstack.org.cn/latest/json-schema-validation.html
# Cargo.toml
valico = "2"
JSON Schema
它通过了整个 JSON-Schema-Test-Suite,除了使用 unicode 偏旁对时远程引用和 maxLength/minLength,它还可以验证您的模式并解释其中存在的问题。
示例
extern crate serde_json;
extern crate valico;
use serde_json::Value;
use valico::json_schema;
use std::fs::File;
fn main() {
let json_schema: Value = serde_json::from_reader(File::open("tests/schema/schema.json").unwrap()).unwrap();
let mut scope = json_schema::Scope::new();
let schema = scope.compile_and_return(json_v4_schema.clone(), false).unwrap();
println!("Is valid: {}", schema.validate(&json_v4_schema).is_valid());
}
JSON Schema 构建器
Valico 提供了一个 valico::json_schema::schema(|scheme| { /* .. */ }) -> json::Json
函数,允许您使用简单的 DSL 生成您的方案。它允许您不使用字符串和原始 JSON 操作,还可以防止某些拼写和类型错误。
builder::schema(|s| {
s.properties(|properties| {
properties.insert("prop1", |prop1| {
prop1.maximum(10f64, false);
});
});
s.pattern_properties(|properties| {
properties.insert("prop.*", |prop| {
prop.maximum(1000f64, false);
});
});
s.additional_properties_schema(|additional| {
additional.maximum(5f64, false)
});
})
待办事项:在此处添加更多关于 JSON Schema 的文档
DSL
基本用法
所有 Valico 东西都是通过 Builder 实例创建的。以下是一个简单的示例,展示了如何创建和设置 Builder
let params = Builder::build(|params| {
params.req_nested("user", Builder::list(), |params| {
params.req_typed("name", json_dsl::string());
params.req_typed("friend_ids", json_dsl::array_of(json_dsl::u64()))
});
});
后续的 params
实例可以用于通过其 process
方法处理一个或多个 JSON 对象,该方法的签名如下:fn process(&self, tree: &mut JsonObject) -> ValicoResult<()>
。
注意,如果需要强制转换,Valico 将会修改借用的 JSON 值。
示例
extern crate valico;
extern crate serde_json;
use valico::json_dsl;
use serde_json::{from_str, to_string_pretty};
fn main() {
let params = json_dsl::Builder::build(|params| {
params.req_nested("user", json_dsl::array(), |params| {
params.req_typed("name", json_dsl::string());
params.req_typed("friend_ids", json_dsl::array_of(json_dsl::u64()))
});
});
let mut obj = from_str(r#"{"user": {"name": "Frodo", "friend_ids": ["1223"]}}"#).unwrap();
let state = params.process(&mut obj, &None);
if state.is_valid() {
println!("Result object is {}", to_string_pretty(&obj).unwrap());
} else {
panic!("Errors during process: {:?}", state);
}
}
您还可以查看 规格说明 以获取更多细节和示例。
验证和强制转换
您可以使用 Builder::build
块定义参数的验证和强制转换选项。参数可以是 可选的 或 必需的。必需参数必须始终存在。可选参数可以省略。
当参数在 JSON 中存在时,所有验证和强制转换都会应用,如果出现问题,则会触发错误。
Builder
以下功能在 Builder 中可用,用于定义参数
// Parameter is required, no coercion
fn req_defined(&mut self, name: &str);
// Parameter is required, with coercion
fn req_typed(&mut self, name: &str, coercer: Box<Coercer>);
// Parameter is required, with coercion and nested checks
fn req_nested(&mut self, name: &str, coercer: Box<Coercer>, nest_def: |&mut Builder|);
// Parameter is required, setup with Param DSL
fn req(&mut self, name: &str, param_builder: |&mut Param|);
// Parameter is optional, no coercion
fn opt_defined(&mut self, name: &str);
// Parameter is optional, with coercion
fn opt_typed(&mut self, name: &str, coercer: Box<Coercer>);
// Parameter is optional, with coercion and nested checks
fn opt_nested(&mut self, name: &str, coercer: Box<Coercer>, nest_def: |&mut Builder|);
// Parameter is required, setup with Param DSL
fn opt(&mut self, name: &str, param_builder: |&mut Param|);
内置强制转换器
可用强制转换器列表
- json_dsl::i64()
- json_dsl::u64()
- json_dsl::f64()
- json_dsl::string()
- json_dsl::boolean()
- json_dsl::null()
- json_dsl::array()
- json_dsl::array_of()
- json_dsl::encoded_array() — 用于字符串编码的数组,例如 "red,green,blue" -> ["red", "green", "blue"]
- json_dsl::encoded_array_of() — 用于某些类型的字符串编码数组,例如 "1,2,3" -> [1, 2, 3]
- json_dsl::object()
使用示例
let params = Builder::build(|params| {
params.req_typed("id", json_dsl::u64());
params.req_typed("name", json_dsl::string());
params.opt_typed("is_active", json_dsl::boolean());
params.opt_typed("tags", json_dsl::array_of(json_dsl::strings()));
});
嵌套处理
您可以指定用于 列表 和 对象 的嵌套处理的规则
let params = Builder::build(|params| {
params.req_nested("user", json_dsl::object(), |params| {
params.req_typed("name", json_dsl::string());
params.opt_typed("is_active", json_dsl::boolean());
params.opt_typed("tags", json_dsl::array_of(json_dsl::strings()));
});
});
let params = Builder::build(|params| {
params.req_nested("users", Builder::list(), |params| {
params.req_typed("name", json_dsl::string());
params.opt_typed("is_active", json_dsl::boolean());
params.opt_typed("tags", json_dsl::array_of(json_dsl::strings()));
});
});
Valico 中的嵌套级别不受限制。
使用 JSON 模式进行验证
DSL 允许在 Builder 级别和 Param 级别使用 JSON 模式验证来验证对象
let params = json_dsl::Builder::build(|params| {
params.req("a", |a| {
a.schema(|schema| {
schema.integer();
schema.maximum(10f64, false);
})
});
});
注意,JSON 模式在强制转换之后验证对象
let mut params = json_dsl::Builder::build(|params| {
params.req("a", |a| {
a.coerce(json_dsl::u64());
a.schema(|schema| {
schema.maximum(10f64, false);
})
});
});
在处理之前,请勿忘记创建 json_schema::Scope
let mut scope = json_schema::Scope::new();
params.build_schemes(&mut scope).unwrap();
参数 DSL
您可以使用 DSL 块以更灵活的方式设置参数
let params = Builder::build(|params| {
params.req("user", |user| {
user.desc("Parameter is used to create new user");
user.coerce(json_dsl::object());
// this allows null to be a valid value
user.allow_null();
user.nest(|params| {
params.req_typed("name", json_dsl::string());
params.opt("kind", |kind| {
kind.coerce(json_dsl::string());
// optional parameters can have default values
kind.default("simeple_user".to_string())
});
});
});
});
参数验证
DSL 支持几种参数验证。它们被认为是过时的,并可能在未来被 JSON 模式验证所取代。
allow_values
参数可以使用 allow_values 限制为特定的值集
let params = Builder::build(|params| {
params.req("kind", |kind| {
kind.coerce(json_dsl::string());
kind.allow_values(&["circle".to_string(), "square".to_string()]);
})
})
reject_values
可以使用 reject_values 拒绝某些值
let params = Builder::build(|params| {
params.req("user_role", |kind| {
kind.coerce(json_dsl::string());
kind.reject_values(&["admin".to_string(), "manager".to_string()]);
})
})
regex
可以使用 Regex 测试字符串值
let params = Builder::build(|params| {
params.req("nickname", |a| {
a.coerce(json_dsl::string());
// force all nicknames to start with "Amazing"
a.regex(regex!("^Amazing"));
})
});
validate_with
有时使用自定义函数作为验证器很有用
let params = Builder::build(|params| {
params.req("pushkin_birthday", |a| {
a.coerce(json_dsl::u64());
fn guess(val: &Json) -> Result<(), String> {
if *val == 1799u.to_json() {
Ok(())
} else {
Err("No!".to_string())
}
}
a.validate_with(guess);
});
});
validate
可以使用自定义验证器。文档正在编写中。
Builder 验证
可以在 Builder DSL 块中指定一些验证器来验证一组参数。
mutually_exclusive
可以将参数定义为互斥的,以确保它们不会同时存在于请求中。
let params = Builder::build(|params| {
params.opt_defined("vodka");
params.opt_defined("beer");
params.mutually_exclusive(&["vodka", "beer"]);
});
可以定义多个集合
let params = Builder::build(|params| {
params.opt_defined("vodka");
params.opt_defined("beer");
params.mutually_exclusive(&["vodka", "beer"]);
params.opt_defined("lard");
params.opt_defined("jamon");
params.mutually_exclusive(&["lard", "jamon"]);
});
警告:永远不要使用任何必需参数定义互斥集合。两个互斥的必需参数将意味着参数永远无效。一个必需参数与一个可选参数互斥将意味着后者永远无效。
exactly_one_of
参数可以定义为 'exactly_one_of',确保恰好选择一个参数。
let params = Builder::build(|params| {
params.opt_defined("vodka");
params.opt_defined("beer");
params.exactly_one_of(["vodka", "beer"]);
});
at_least_one_of
参数可以定义为 'at_least_one_of',确保至少选择一个参数。
let params = Builder::build(|params| {
params.opt_defined("vodka");
params.opt_defined("beer");
params.opt_defined("wine");
params.exactly_one_of(["vodka", "beer", "wine"]);
});
validate_with
有时使用自定义函数作为验证器很有用
let params = Builder::build(|params| {
params.req_defined("monster_name");
fn validate_params(_: &JsonObject) -> Result<(),String> {
Err("YOU SHALL NOT PASS".to_string())
}
params.validate_with(validate_params);
});
validate
可以使用自定义验证器。文档正在编写中。
为其他目标构建
Web Assembly
对于 WebAssembly,启用 js
功能
# Cargo.toml
valico = { version = "2", features = ["js"] }
依赖
~9-17MB
~276K SLoC