Vert.x Json Schema
Vert.x Json Schema组件提供了一个异步可扩展的 Json Schema 规范实现。 你可以使用 Json Schema 去校验每一个json结构的数据。这个组件提供以下特性:
-
实现了 OpenAPI 3 dialect.
-
非阻塞的
$ref
引用和缓存 -
使用
JsonPointer
检索缓存 -
支持同步和异步校验
-
支持校验树的扩展,允许添加自定义关键词和自定义格式条件
-
通过DSL来构建schemas
使用 Vert.x Json Schema
为了使用 Vert.x Json Schema ,需要在构建配置文件中添加如下 依赖:
-
Maven (在
pom.xml
文件中):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-json-schema</artifactId>
<version>4.0.3</version>
</dependency>
-
Gradle (在
build.gradle
文件中):
dependencies {
compile 'io.vertx:vertx-json-schema:4.0.3'
}
相关概念
SchemaParser 和 SchemaRouter
SchemaParser
组件负责将json数据结构的schema解析成 Schema
实例。
SchemaRouter
组件负责处理schema解析后的缓存以及相关的 $ref
引用。
当处理 $ref
的引用或者使用 SchemaParser
解析新的schema时,这个schema就会被缓存到相应的 SchemaRouter
中去。
SchemaParser
可以进行扩展并且支持自定义关键词和自定义格式。
当前可用的 SchemaParser
有:
-
Draft201909SchemaParser
for Json Schema Draft 2019-09 -
Draft7SchemaParser
for Json Schema Draft 7 -
OpenAPI3SchemaParser
for OpenAPI 3 dialect
解析schema
要开始解析schema,首先你需要一个能匹配你的schema 方言 的 schema router 和 schema parser。 以实例化一个 draft 2019-09 的 schema parser 为例:
SchemaRouter schemaRouter = SchemaRouter.create(vertx, new SchemaRouterOptions());
SchemaParser schemaParser = SchemaParser.createDraft201909SchemaParser(schemaRouter);
对于不同的 SchemaParser
, 你可以复用同一个 SchemaRouter
实例;而且还可以使用同一个 SchemaParser
来解析不同的 Schema
。
现在你可以解析schema了:
Schema schema = parser.parse(object, schemaPointer);
解析schema时,必须要指定一个 schema pointer ,这个 pointer 是定位 schema 的唯一标识。
如果你没有指定 schema pointer,那么 SchemaParser
默认会生成一个。
Schema schema = parser.parse(object);
schema.getScope(); // 获取schema的生成作用域 (schema pointer)
重要
|
需要注意的是,当使用 |
校验
一个schema可以有两种状态:
-
同步状态: 校验树支持同步校验,你可以分别使用
validateSync
和validateAsync
来校验你的json。 -
异步状态:校验树存在一个或多个分支时需要使用异步校验,你必须使用
validateAsync
方法来校验json,如果你使用validateSync
来校验则会抛出NoSyncValidationException
异常。
在异步状态下校验 schema:
schema.validateAsync(json).onComplete(ar -> {
if (ar.succeeded()) {
// 校验成功
} else {
// 校验失败
ar.cause(); // 包含校验的异常情况
}
});
在同步状态下校验schema:
try {
schema.validateSync(json);
// 校验成功
} catch (ValidationException e) {
// 校验失败
} catch (NoSyncValidationException e) {
// 必须使用异步校验,不能使用同步校验
}
你可以使用 isSync
方法来获取schema的当前状态。
schema可以实时切换状态,比如,如果你有一个schema使用 $ref
引用了外部的schema,
此时它处于异步状态,在第一次校验之后,外部schema被缓存了,这时schema将会切换到同步状态。
注意
|
如果schema在同步状态下使用 |
自定义格式
你可以在解析schemas之前使用校验关键字 format
来自定义数据格式。
parser.withStringFormatValidator("firstUppercase", str -> Character.isUpperCase(str.charAt(0)));
JsonObject mySchema = new JsonObject().put("format", "firstUppercase");
Schema schema = parser.parse(mySchema);
自定义关键词
每当你想要添加一个新的关键词类型时,你必须要实现 ValidatorFactory
,
然后使用 withValidatorFactory
提供一个实例给 SchemaParser
。
当解析开始时,SchemaParser
将会调用每一个注册的工厂的 canConsumeSchema
方法。
如果工厂可以使用这个schema,那么就会调用 createValidator
方法。
这个方法返回一个执行校验的 Validator
对象实例,
如果在 Validator
初始化过程中发生错误,将会抛出 SchemaException
异常。
你可以自定义以下三种类型的关键词:
-
总是同步校验输入的关键词
-
总是异步校验输入的关键词
-
可变状态的关键词
同步关键词
同步校验器必须要实现 SyncValidator
接口。
在下面的例子中,我们自定义一个关键词,这个关键词需要校验json对象中的属性数值是否符合给定的多个预设值。
`link:../../apidocs/examples/PropertiesMultipleOfValidator.html[PropertiesMultipleOfValidator]`
在定义了关键词校验器之后,我们就可以定义工厂了:
`link:../../apidocs/examples/PropertiesMultipleOfValidatorFactory.html[PropertiesMultipleOfValidatorFactory]`
现在我们可以挂载这个新的校验工厂:
parser.withValidatorFactory(new PropertiesMultipleOfValidatorFactory());
JsonObject mySchema = new JsonObject().put("propertiesMultipleOf", 2);
Schema schema = parser.parse(mySchema);
异步关键词
同步校验器必须要实现 AsyncValidator
接口。
在这个例子中,我添加了一个关键词,这个关键词从Vert.x Event bus中检索一个枚举值
`link:../../apidocs/examples/AsyncEnumValidator.html[AsyncEnumValidator]`
在定义了关键字校验器之后,我们就可以定义工厂了:
`link:../../apidocs/examples/AsyncEnumValidatorFactory.html[AsyncEnumValidatorFactory]`
现在我们可以挂载这个新的校验工厂:
parser.withValidatorFactory(new AsyncEnumValidatorFactory(vertx));
JsonObject mySchema = new JsonObject().put("asyncEnum", "enums.myapplication");
Schema schema = parser.parse(mySchema);
用代码来构建schema
如果你想要使用代码来构建schema,你可以使用附带的DSL。目前只有Draft-7支持这个特性。
创建schema
在 Schemas
内部提供了schema创建的静态方法:
SchemaBuilder intSchemaBuilder = intSchema();
SchemaBuilder objectSchemaBuilder = objectSchema();
使用关键词
对于每一个schema,你是否可以使用 Keywords
方法来构建关键词,
这取决于schema的类型:
stringSchema()
.with(format(StringFormat.DATETIME));
arraySchema()
.with(maxItems(10));
schema() // 生成同时接收数组和整数的schema
.with(type(SchemaType.ARRAY, SchemaType.INT));
定义schema的结构
根据你创建的schema,你可以定义结构。
使用属性schema和其他属性schema来创建一个对象类型的schema:
objectSchema()
.requiredProperty("name", stringSchema())
.requiredProperty("age", intSchema())
.additionalProperties(stringSchema());
创建一个数组类型的schema:
arraySchema()
.items(stringSchema());
创建元组类型的schema:
tupleSchema()
.item(stringSchema()) // 第一个元素
.item(intSchema()) // 第二个元素
.item(booleanSchema()); // 第三个元素
$ref
和 别名
你可以使用 Schemas.ref
方法来添加一个 $ref
schema。
通过 id
来指定对应schema的 $id
关键词。
你也可以使用别名来引用通过dsl定义的schema。你可以使用 alias
来为一个schema设置别名。
这样你就可以使用 Schemas.refToAlias
来根据别名引用schema。
intSchema()
.alias("myInt");
objectSchema()
.requiredProperty("anInteger", refToAlias("myInt"));
使用schema
在定义好schama后,你可以调用 build
方法来解析和使用这个schema:
Schema schema = objectSchema()
.requiredProperty("name", stringSchema())
.requiredProperty("age", intSchema())
.additionalProperties(stringSchema())
.build(parser);