跳到主要内容

声明 dialect

JSON Schema 的一个版本称为 dialect。dialect 表示可用于评估模式的一组关键字和语义。每个 JSON Schema 版本都是 JSON Schema 的新 dialect。JSON Schema 为您提供了一种声明模式符合哪种 dialect 的方法,并提供了描述您自己的自定义 dialect 的方法。

$schema

$schema关键字用于声明模式是针对哪种 JSON dialect 编写的。$schema 关键字的值也是模式的标识符,可用于根据 dialect$schema 标识验证模式是否有效。描述另一个模式的模式称为“元模式”。

$schema适用于整个文档并且必须在根级别。它不适用于外部引用的 ( $ref, $recursiveRef) 文档。这些模式需要声明自己的 $schema.

如果$schema未使用,则实现可能允许您在外部指定一个值,或者它可能会假设应该使用哪个规范版本来评估模式。建议所有 JSON 模式都有一个$schema关键字来与读者和工具进行交流,以了解预期的规范版本。因此,大多数情况下,您会希望在架构的根目录下使用它:

"$schema": "https://json-schema.org/draft/2019-09/schema"

Draft 4 的标识符是http://json-schema.org/draft-04/schema#

Draft 4 定义了一个没有特定 dialect ( http://json-schema.org/schema#)的$schema,这意味着使用最新的 dialect。这已被弃用,不应再使用。

您可能会遇到对 Draft 5 的引用。没有 JSON Schema 的 Draft 5 版本。Draft 5 指的是 Draft 4 版本的无变化修订版。它不会添加、删除或更改任何功能。它只更新参考资料、进行澄清和修复错误。Draft 5 描述了 DraftDraft4 版本。如果您来这里寻找有关 Draft 5 的信息,您会在 Draft 4 下找到它。我们不再使用“Draft”术语来指代补丁版本以避免这种混淆。

Draft 6 的标识符是http://json-schema.org/draft-06/schema#

Draft 7 的标识符是http://json-schema.org/draft-07/schema#

词汇表

2019-09 Draft 中的新内容:文档即将推出

Draft4-7 在引入 Vocabularies 之前,您仍然可以使用自定义关键字扩展 JSON Schema,但该过程不太正式。您需要的第一件事是包含自定义关键字的元架构。最好的方法是为要扩展的版本制作元模式的副本,并对副本进行更改。您需要选择一个自定义 URI 来标识您的自定义版本。此 URI 不能是用于标识官方 JSON 架构规范 Draft 的 URI 之一,并且可能应该包含您拥有的域名。您可以将此 URI 与$schema关键字一起使用来声明您的模式使用您的自定义版本。

笔记并非所有实现都支持自定义元模式和自定义关键字实现。

指南

JSON Schema 的优势之一是它可以用 JSON 编写并在各种环境中使用。例如,它可用于前端和后端 HTML 表单验证。使用自定义词汇表的问题在于,您想要使用模式的每个环境都需要了解如何评估词汇表的关键字。元模式可用于确保模式编写正确,但每个实现都需要自定义代码来了解如何评估词汇表的关键字。

元数据关键字是最具互操作性的,因为它们不影响验证。例如,您可以添加units关键字。对于合规的验证器,将始终按预期生效。

{
"type": "number",
"units": "kg"
}

42 // OK
"42" // not OK

自定义关键字的下一个最佳候选者是不应用其他模式且不修改现有关键字行为的关键字。isEven关键字是一个例子,在某些语境下验证比没有验证要好,例如在浏览器中验证 HTML 表单时,此模式的性能将达到预期。完全验证仍然是需要的,并且应该使用可以理解自定义关键字的验证器。

{
"type": "integer",
"isEven": true
}

2 // OK
3 // OK,这通过因为验证器不理解 `isEven`
"3" // not OK,模式没有因为不理解 `isEven`而完全受损

互操作性最差的自定义关键字类型是应用其他模式或修改现有关键字行为的自定义关键字。一个例子就是requiredProperties,这个关键字声明属性并使它们成为必需属性。以下示例显示了在使用不理解自定义关键字的验证器进行校验时,模式如何变得几乎无用。这并不一定意味着这requiredProperties对关键字来说是个坏主意,只是说如果模式在不理解自定义关键字的上下文中使用时不是一个好的选择。

{
"type": "object",
"requiredProperties": {
"foo": { "type": "string"}
}
}

{ "foo": "bar" } // OK
{} // OK,因为`requiredProperties`不被理解
{ "foo": 42 } //ok,因为`requiredProperties`不被理解