JSON Schema

https://json-schema.org/draft/2020-12/schema
MIME: application/schema+json
https://www.schemastore.org/json/
该网站记录了常见格式的JSON Schema.
  • anyOf: 符合数组中的任何一个Schema, 解析器在发现第一个符合条件的Schema后就会结束.
  • oneOf: 只符合数组中的一个Schema, 解析器会校验每一个Schema, 确保只有一个Schema符合条件.
  • allOf: 符合数组中的所有Schema.
  • not: 不满足此子Schema.
在使用逻辑子模式时, 如果当前对象已经包含了其他字段, 则会将这些字段视作共同条件.
{
"type": "number"
, "oneOf": [
{ "multipleOf": 5 }
, { "multipleOf": 3 }
]
}
等价于
{
"oneOf": [
{ "type": "number", "multipleOf": 5 }
, { "type": "number", "multipleOf": 3 }
]
}
一个URI, 用于标记此JSON的格式, 本身也是一个Schema.
该属性用于标记使用的JSON Schema版本, 代码编辑器依此获得自动完成的提示.
此JSON Schema的URI标识符, 它只是作为标识符使用, 不一定可以在网络上访问.
尽管大多数 $id 字段的值会使用绝对URI, 但 $id 有时也用 / 开头的相对URI.
对于支持网络的解析器, 如果Schema使用相对URI, 则会根据该JSON文件所处的URI生成它的绝对URI.
如果一个Schema没有 $id 字段, 意味着它是匿名的.
如果该JSON文件在网络上, 则会将JSON文件的URI当作该Schema的 $id.
  • title: 该内容的名称, string.
  • description: 该内容的描述, string.
  • type: 该Schema的类型, 必须是JSON类型中的一种或多种, string | string[].
  • default: 默认值, 通常是被表单生成器使用, 值的类型取决于该内容的类型.
  • deprecated: 表示该Schema预定被弃用, 将在未来版本移除, boolean.
  • $comment: Schema作者专用的注释字段, 不会显示给普通用户.
  • readOnly: boolean, 如果为真, 表示该值不能被应用程序写入, 应用程序发起的相关修改会被拒绝或忽略.
  • writeOnly: boolean, 如果为真, 表示该值不能被应用程序读取, 它可以在更新时被写入, 但应用程序无法看到它.
readOnly和writeOnly在语义上具有排他性, 但JSON Schema的设计者似乎不这么想, 此事实导致这两个字段同时使用会带来混乱, 不建议使用.
  • properties: 该对象字段的schema, Record<string, Schema>.
  • required: 该对象必要的字段, string[]
  • items: 该数组元素的Schema.
元组通过 prefixItems 间接实现, 此方式允许数据超出元组所需的元素数量.
{
"type": "array"
, "prefixItems": [
{ "type": "number" }
, { "type": "string" }
, { "enum": ["Street", "Avenue", "Boulevard"] }
, { "enum": ["NW", "NE", "SW", "SE"] }
]
}
{
"enum": ["red", "green", "blue"]
}
表示Schema是一个常数.
{
"const": "Hello World"
}
$ref 字段被来引用其他的JSON文件.
字段的值为URI, URI应与被引用文件的 $id 值相符.
使用相对URI时, 是相对于当前的Base URI.
引用同一个命名空间下的Schema时, 通常会使用以 / 开头的相对URI或绝对URI.
对于在 $defs 里定义的Schema, 需要以 #/$defs/ 为URI前缀来引用.
$ref 支持递归自身, 只需要将值设置为 #.
可以通过锚点来访问一个JSON Schema的子模式:
https://example.com/schemas/address#/properties/street_address
意味着访问address文件里定义的根据JSON路径 /properties/street_address 找到的模式.
表示此字段依赖于其他字段, 如果没有其他字段, 则此字段不被允许使用.
以下Schema里, credit_card依赖于billing_address字段, 如果只提供credit_card字段, 则会验证失败:
{
"type": "object"
, "properties": {
"name": { "type": "string" }
, "credit_card": { "type": "number" }
, "billing_address": { "type": "string" }
}
, "dependentRequired": {
"credit_card": ["billing_address"]
}
}
比dependentRequired更进一步, 不仅是依赖字段, 还依赖字段符合特定的Schema.
credit_card依赖于billing_address字段, 且billing_address字段必须是一个字符串:
{
"type": "object"
, "properties": {
"name": { "type": "string" }
, "credit_card": { "type": "number" }
}
, "dependentSchemas": {
"credit_card": {
"properties": {
"billing_address": { "type": "string" }
}
, "required": ["billing_address"]
}
}
}
根据if-then-else分支语句来决定要使用哪个子Schema.
单个条件语句(如果未提供country字段, 也会落入else分支):
{
"type": "object"
, "properties": {
"street_address": { "type": "string" }
, "country": {
"enum": ["USA", "Canada"]
}
}
, "if": {
"properties": { "country": { "const": "USA" } }
}
, "then": {
"properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
}
, "else": {
"properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
}
}
可翻译为:
if (this.country === 'USA') {
assert(this.postal_code.match(/[0-9]{5}(-[0-9]{4})?/))
} else {
assert(this.postal_code.match(/[A-Z][0-9][A-Z] [0-9][A-Z][0-9]/))
}
组合多个条件语句(会编写出反直觉和难以阅读的模式, 因此不推荐使用),
后两个if里的required字段是必要的, 不可省略:
{
"type": "object"
, "properties": {
"street_address": { "type": "string" }
, "country": {
"enum": ["USA", "Canada", "Netherlands"]
}
},
"allOf": [
{
"if": {
"properties": { "country": { "const": "USA" } }
}
, "then": {
"properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
}
}
, {
"if": {
"properties": { "country": { "const": "Canada" } }
, "required": ["country"]
}
, "then": {
"properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
}
}
, {
"if": {
"properties": { "country": { "const": "Netherlands" } }
, "required": ["country"]
}
, "then": {
"properties": { "postal_code": { "pattern": "[0-9]{4} [A-Z]{2}" } }
}
}
]
}
可翻译为:
if (this.country === 'USA') {
assert(this.postal_code.match(/[0-9]{5}(-[0-9]{4})?/))
} else if (this.country === 'Canada') {
assert(this.postal_code.match(/[A-Z][0-9][A-Z] [0-9][A-Z][0-9]/))
} else if (this.country === 'Netherlands') {
assert(this.postal_code.match(/[0-9]{4} [A-Z]{2}/))
} else {
assert(this.postal_code.match(/[0-9]{5}(-[0-9]{4})?/)) // USA的模式
}
在过去的版本里是 definitions.
定义创建可以被引用的内部项, Map<string, Schema>,
项的键是被引用项的URI标识符.
不太常用的字段, 可以主动定义子模式的名称, 从而被 $ref 引用.
值需要以 # 开头, 例如 { $anchor: "#street_address" }
可以在string类型的Schema里表示多媒体内容,
为此需要将 contentMediaType 字段设置为多媒体内容的MIME类型.
contentEncoding 字段代表多媒体的编码, 最常用的是 base64.
很多JSON Schema工具都不能处理引用的外部资源,
一种解决方法是将这些外部资源打包成一个JSON文件.
实际的打包是将 $ref 的外部文件以 $defs 的形式定义在同一个文件内来实现的.