35 个不稳定版本
0.18.0 | 2024年5月7日 |
---|---|
0.17.1 | 2023年7月5日 |
0.17.0 | 2023年3月16日 |
0.16.1 | 2022年10月20日 |
0.2.0 | 2020年3月30日 |
#9 in Web 编程
774,091 每月下载量
在 146 个 crate (78 直接) 中使用
575KB
14K SLoC
jsonschema
一个 JSON 模式验证器的实现。它将模式编译成验证树,以尽可能快地进行验证。
支持的草案
- 草案 7(除可选的
idn-hostname.json 测试用例外)
- 草案 6
- 草案 4(除可选的
bignum.json 测试用例外)
部分支持草案(一些关键字尚未实现)
- 草案 2019-09(需要启用
draft201909
功能) - 草案 2020-12(需要启用
draft202012
功能)
# Cargo.toml
jsonschema = "0.18"
要验证某些模式并获取验证错误(如果有)
use jsonschema::JSONSchema;
use serde_json::json;
fn main() {
let schema = json!({"maxLength": 5});
let instance = json!("foo");
let compiled = JSONSchema::compile(&schema)
.expect("A valid schema");
let result = compiled.validate(&instance);
if let Err(errors) = result {
for error in errors {
println!("Validation error: {}", error);
println!(
"Instance path: {}", error.instance_path
);
}
}
}
每个错误都有一个 instance_path
属性,它指示验证实例中错误部分的路径。它可以通过 .to_string()
或通过 Vec<String>
转换为 JSON 指针。
如果您只需要知道文档是否有效(这更快)
use jsonschema::is_valid;
use serde_json::json;
fn main() {
let schema = json!({"maxLength": 5});
let instance = json!("foo");
assert!(is_valid(&schema, &instance));
}
或使用编译后的模式(推荐)
use jsonschema::JSONSchema;
use serde_json::json;
fn main() {
let schema = json!({"maxLength": 5});
let instance = json!("foo");
// Draft is detected automatically
// with fallback to Draft7
let compiled = JSONSchema::compile(&schema)
.expect("A valid schema");
assert!(compiled.is_valid(&instance));
}
输出样式
jsonschema
支持 Draft 2019-09 的 basic
和 flag
输出样式,因此您可以使用 serde
序列化验证结果
use jsonschema::{Output, BasicOutput, JSONSchema};
use serde_json::json;
fn main() {
let schema_json = json!({
"title": "string value",
"type": "string"
});
let instance = json!("some string");
let schema = JSONSchema::compile(&schema_json)
.expect("A valid schema");
let output: BasicOutput = schema.apply(&instance).basic();
let output_json = serde_json::to_value(output)
.expect("Failed to serialize output");
assert_eq!(
output_json,
json!({
"valid": true,
"annotations": [
{
"keywordLocation": "",
"instanceLocation": "",
"annotations": {
"title": "string value"
}
}
]
})
);
}
自定义关键字
jsonschema
允许您通过定义自定义关键字来实现自定义验证逻辑。要使用您自己的关键字,您需要实现 Keyword
trait 并通过 with_keyword
方法将其添加到 JSONSchema
实例中
use jsonschema::{
paths::{JSONPointer, JsonPointerNode},
ErrorIterator, JSONSchema, Keyword, ValidationError,
};
use serde_json::{json, Map, Value};
use std::iter::once;
struct MyCustomValidator;
impl Keyword for MyCustomValidator {
fn validate<'instance>(
&self,
instance: &'instance Value,
instance_path: &JsonPointerNode,
) -> ErrorIterator<'instance> {
// ... validate instance ...
if !instance.is_object() {
let error = ValidationError::custom(
JSONPointer::default(),
instance_path.into(),
instance,
"Boom!",
);
Box::new(once(error))
} else {
Box::new(None.into_iter())
}
}
fn is_valid(&self, instance: &Value) -> bool {
// ... determine if instance is valid ...
true
}
}
// You can create a factory function, or use a closure to create new validator instances.
fn custom_validator_factory<'a>(
// Parent object where your keyword is defined
parent: &'a Map<String, Value>,
// Your keyword value
value: &'a Value,
// JSON Pointer to your keyword within the schema
path: JSONPointer,
) -> Result<Box<dyn Keyword>, ValidationError<'a>> {
// You may return validation error if the keyword is misused for some reason
Ok(Box::new(MyCustomValidator))
}
fn main() {
let schema = json!({"my-type": "my-schema"});
let instance = json!({"a": "b"});
let compiled = JSONSchema::options()
// Register your keyword via a factory function
.with_keyword("my-type", custom_validator_factory)
// Or use a closure
.with_keyword("my-type-with-closure", |_, _, _| Ok(Box::new(MyCustomValidator)))
.compile(&schema)
.expect("A valid schema");
assert!(compiled.is_valid(instance));
}
引用解析和 TLS
默认情况下,jsonschema
通过 reqwest
解析 HTTP 引用,但不支持 TLS。如果您想解析 HTTPS,您需要在 reqwest
中启用 TLS 支持
reqwest = { version = "*", features = [ "rustls-tls" ] }
否则,您可能会遇到如下的验证错误:无效的 URL,方案不是 http
。
状态
此库功能齐全,可供使用,但其 API 仍在向 1.0 API 发展。
绑定
运行测试
在 jsonschema/ 中的测试依赖于 JSON Schema 测试套件。在调用 cargo test
之前,请下载套件
$ git submodule init
$ git submodule update
以下命令将套件克隆到 jsonschema/tests/suite/。
现在,进入 jsonschema
目录并运行 cargo test
。
$ cd jsonschema
$ cargo test
性能
与其他用 Rust 编写的 JSON Schema 验证器进行了比较 - jsonschema_valid==0.5.2
和 valico==4.0.0
。
测试机器 i8700K (12 核心处理器),32GB RAM。
输入值和模式
- Zuora OpenAPI 模式(
zuora.json
)。与 OpenAPI 3.0 JSON 模式(openapi.json
)进行验证。 - Kubernetes Swagger 模式(
kubernetes.json
)。与 Swagger JSON 模式(swagger.json
)进行验证。 - 加拿大边境(GeoJSON 格式)(
canada.json
)。模式来自 GeoJSON 网站(geojson.json
)。 - 音乐会数据目录(
citm_catalog.json
)。模式通过 infers-jsonschema 推断,并手动调整(citm_catalog_schema.json
)。 Fast
来自 fastjsonschema 基准测试(fast_schema.json
,fast_valid.json
和fast_invalid.json
)。
案例 | 模式大小 | 实例大小 |
---|---|---|
OpenAPI | 18 KB | 4.5 MB |
Swagger | 25 KB | 3.0 MB |
加拿大 | 4.8 KB | 2.1 MB |
CITM 目录 | 2.3 KB | 501 KB |
Fast(有效) | 595 B | 55 B |
Fast(无效) | 595 B | 60 B |
以下是每个竞争者进行验证的平均时间。比率是使用其 validate
方法针对编译的 JSONSchema
提供的。 is_valid
方法更快,但只返回布尔值
案例 | jsonschema_valid | valico | jsonschema(验证) | jsonschema(is_valid) |
---|---|---|---|---|
OpenAPI | - (1) | - (1) | 3.500 毫秒 | 3.147 毫秒(x0.89) |
Swagger | - (2) | 180.65 毫秒(x32.12) | 5.623 毫秒 | 3.634 毫秒(x0.64) |
加拿大 | 40.363 毫秒(x33.13) | 427.40 毫秒(x350.90) | 1.218 毫秒 | 1.217 毫秒(x0.99) |
CITM 目录 | 5.357 毫秒(x2.51) | 39.215 毫秒(x18.44) | 2.126 毫秒 | 569.23 微秒(x0.26) |
Fast(有效) | 2.27 微秒(x4.87) | 6.55 微秒(x14.05) | 465.89 纳秒 | 113.94 纳秒(x0.24) |
Fast(无效) | 412.21 纳秒(x0.46) | 6.69 微秒(x7.61) | 878.23 纳秒 | 4.21 纳秒(x0.004) |
备注
-
jsonschema_valid
和valico
无法处理与正则表达式^\\/
匹配的有效路径实例。 -
jsonschema_valid
无法解析本地引用(例如#/definitions/definitions
)。
您可以在 benches/jsonschema.rs
中找到基准代码,Rust 版本是 1.78
。
支持
如果您想讨论有关此库的任何内容,请加入我们的 gitter!
依赖关系
~9–21MB
~330K SLoC