Json-schema
前端与服务器端的交互过程,大部分时候是使用的json格式
对于json还是比较了解,可是json-schema是什么?
json–JavaScript Object Notation JavaScript对象表示法
json-schema是一个用于验证json数据格式的工具,它本身也是使用json语言编写的
Json Schema定义了一套词汇和规则,这套词汇和规则用来定义Json元数据,且元数据也是通过Json数据形式表达的。Json元数据定义了Json数据需要满足的规范,规范包括成员、结构、类型、约束等
Json-schema示例
json-schema举例:
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"$id": "https://json-schema.org/draft/2019-09/schema",
"$vocabulary": {
"https://json-schema.org/draft/2019-09/vocab/core": true,
"https://json-schema.org/draft/2019-09/vocab/applicator": true,
"https://json-schema.org/draft/2019-09/vocab/validation": true,
"https://json-schema.org/draft/2019-09/vocab/meta-data": true,
"https://json-schema.org/draft/2019-09/vocab/format": false,
"https://json-schema.org/draft/2019-09/vocab/content": true
},
"$recursiveAnchor": true,
"title": "Core and Validation specifications meta-schema",
"allOf": [
{"$ref": "meta/core"},
{"$ref": "meta/applicator"},
{"$ref": "meta/validation"},
{"$ref": "meta/meta-data"},
{"$ref": "meta/format"},
{"$ref": "meta/content"}
],
"type": ["object", "boolean"],
"properties": {
"definitions": {
"$comment": "While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.",
"type": "object",
"additionalProperties": { "$recursiveRef": "#" },
"default": {}
},
"dependencies": {
"$comment": "\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"",
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$recursiveRef": "#" },
{ "$ref": "meta/validation#/$defs/stringArray" }
]
}
}
}
}
在上述文件中,有些是json-schema规定的特殊字符,也即具有特殊涵义的字符,我们称之为关键字或保留字,有些是根据我们的需要随便编写的相关内容,
关键字说明
关键字 | 描述 | 示例 |
---|---|---|
$schema | 主要用于声明当前文件使用的json模式,遵守的是那个版本json模式的规范 | 上述示例是遵守2019-09发布的那个版本 |
$id | 用于作为模式的唯一标识符,一般指向一个自主域名。方便后续引用 | |
$ref | 引用一个定义的模式 | |
$vocabulary | ||
$recursiveAnchor | ||
$recursiveRef | ||
$comment | 仅仅是为模式添加注释用(New in draft 7) | |
type | 类型:string\number\boolean\array\object\null | |
properties | 属性,用于定义对象中的属性 | |
required | 用于定义对象中必须含有的属性 | |
enum | 表示json数据的取值只能是list中的某个 | 数组 |
title | 标题,用它给我们的模式提供了标题 | |
description | 关于模式的描述。 | |
default | 默认值 | |
example | 一个符合约束条件的模式示例 |
title,description,default,example只作为描述作用,不影响对数据的校验。
对复杂结构的支持包括定义和引用。当多个元素使用相同的校验模式时,可以将相同的结构校验定义成一个“类型”,需要使用该“类型”时,可以通过其路径或id来引用
definations-用于定义通用类型模式
定义一个类型,并不需要特殊的关键字。通常的习惯是在root节点的 definations 下面,定义需要多次引用的schema。definations是一个json对象,key是想要定义的“类型”的名称,value是一个json schema
{
"definitions": {
"address": {//定义的一个通用的模式
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
},
"type": "object",
"properties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": { "$ref": "#/definitions/address" }
}
}
$ref
上例中定义了一个address的schema,并且在两个地方通过路径的方式引用了它,#/definitions/address表示从根节点开始的路径
$id
{
"definitions": {
"address": {//定义的一个通用的模式
"type": "object",
"$id" : "address",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
},
"type": "object",
"properties": {
"billing_address": { "$ref": "#address"},
"shipping_address": { "$ref":"#address"}
}
}
可以在上面的定义中加入id属性,这样可以通过id属性的值对该schema进行引用,而不需要完整的路径。
type
定义模式属性的类型,可以是单选也可以提供多个类型:
type的可选值包括:string\number\boolean\array\object\null
仅有一个类型可选:{ "type": "string" }
可以有多个类型可选:{ "type": ["number", "string"] }
当type与enum发生冲突的时候,以type约束为先
:
{
"type": "string",
"enum": ["red", "amber", "green", null]
}
null值与"type": "string"冲突,此时若选值null则检测不通过
约束条件
string 类型的约束条件
关键字 | 描述 | 取值类型 |
---|---|---|
maxLength | 字符串实例字符的最大长度(非负) | ≥0 |
minLength | 字符串实例字符的最小长度(非负) | ≥0 |
pattern | 限定字符串应符合的表达式条件,符合则有效 | 表达式 |
format | Json Schema内建的一些规则,对字符串的格式做约束,例如电子邮件、日期、域名等 |
format包括"date", “time”, “date-time”, “email”, “hostname”,“ipv4”,"uri"等
“json-pointer”,“regex”
number类型的约束条件
number:数字类型
integer:必须是整数
关键字 | 描述 | 取值类型 |
---|---|---|
minimum | 表示可以接受的最小值。 x ≥ minimum | 数值型 |
maximum | 表示可以接受的最大值。 x ≤ maximum | 数值型 |
exclusiveMinimum | 开区间最小值,排除等于的情况。x > exclusiveMinimum | 数值型 |
exclusiveMaximum | 开区间最大值,排除等于的情况。x < exclusiveMaximum | 数值型 |
multipleOf | 要求数值必须是该指定值的整数倍 | 数值型 |
array类型的约束条件
关键字 | 描述 | 取值类型 |
---|---|---|
minItems | 表示数组内最少元素个数 | 数值型 |
maxItems | 表示数组内最多元素个数 | 数值型 |
items | 要求数组内每个成员都是某种类型 | {“type”: “number”}或者[{“type”: “number”},{“type”: “string”}] |
additionalItems | 数组是否允许额外成员,配合items使用 | booloan,或限制条件 |
uniqueItems | 约束数组中每项不得重复 | booloan |
contains | 最少有一个符合条件 |
示例:
"type": "array",
"items": [
{//0
"type": "number"
},
{//1
"type": "string"
},
{//2
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
},
{//4
"type": "string",
"enum": ["NW", "NE", "SW", "SE"]
}
],
"minItems": 1,
"maxItems": 5,
"additionalItems": {
"type": "string",
"minLength": 2
},
"uniqueItems": true
}
items & additionalItems
items列出了多个约束条件时,对应索引的项如果存在必须符合约束条件
-
additionalItems属性不存在
- 数组长度小于items,只要存在的项符合约束条件即可,也即数组长度可以小于items
- 数组长度大于items且额外元素没有约束条件
-
存在additionalItems属性,数组的长度受限于 additionalItems:
- 数组长度若小于items,只要存在的项符合约束条件即可,不受 additionalItems影响
- 如果additionalItems为true,没有额外约束,数组长度可以大于items,因为后面的元素没有对应索引的items约束条件因此无约束
示例:
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "string"
},
{
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
},
{
"type": "string",
"enum": ["NW", "NE", "SW", "SE"]
}
],
"additionalItems": true
}
- 如果additionalItems 有额外的约束,额外的元素必须符合additionalItems 的约束条件
"type": "array",
"items": [
{//0
"type": "number"
},
{//1
"type": "string"
}
],
"minItems": 1,
"maxItems": 5,
"additionalItems": {
"type": "string",
"minLength": 2
},
"uniqueItems": true
}
- 如果additionalItems为 false,数组长度只能<=items的长度
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "string"
},
{
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
},
{
"type": "string",
"enum": ["NW", "NE", "SW", "SE"]
}
],
"additionalItems": false
}
contains(New in draft 6)
示例:
{
"type": "array",
"contains": {
"type": "number"
}
}
e.g :["life", "universe", "everything", 42]//最少有一个符合条件
object类型的约束条件
关键字 | 描述 | 取值类型 |
---|---|---|
required | 约束对象必须具有的属性字段 | 数组 |
properties | 用于定义对象属性和对应值的类型,以及用于 JSON 文件中的最小值和最大值。 | |
propertyNames | 用于定义对象properties中的属性名称需要满足的约束 | |
patternProperties | 批量定义对象Schema | |
dependencies | 规定某些属性之间的依赖,不能在依赖属性缺席的情况下单独出现,属于数据完整性方面的约束。 | |
additionalProperties | 规定object类型是否允许出现不在properties中规定的属性 | 可以取true/false,或者直接设置约束规则 |
minProperties | 规定最少有几个属性成员 | |
maxProperties | 规定最多有几个属性成员 | |
const | 用于设定属性的值 |
propertyNames(New in draft 6)
示例:
{
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
}
}
const(New in draft 6)
设定值后不允许属性设置为其他值
{ “const”: “United States of America” }
等价于
{ “enum”: [ “United States of America” ] }
dependencies
属性间的依赖
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" },
"billing_address": { "type": "string" }
},
"required": ["name"],
"dependencies": {
"credit_card": ["billing_address"],
"billing_address": ["credit_card"]
}
}
单独定义依赖的属性模式
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" }
},
"required": ["name"],
"dependencies": {//credit_card依赖的属性
"credit_card": {
"properties": {
"billing_address": { "type": "string" }
},
"required": ["billing_address"]
}
}
}
只要credit_card属性存在,billing_address必须存在
additionalProperties
用法类似于additionalItems
additionalProperties不受properties与patternProperties的约束条件限制
{
"type": "object",
"properties": {
"builtin": { "type": "number" }
},
"patternProperties": {
"^S_": { "type": "string" },
"^I_": { "type": "integer" }
},
"additionalProperties": { "type": "string" }
}
逻辑组合的约束条件
关键字 | 描述 | 取值类型 |
---|---|---|
allOf | 满足所有约束条件,"allOf"的内容是一个数组,数组内的成员都是内嵌的Json Schema | |
anyOf | 满足anyOf数组中的任意个Schema | |
oneOf | 满足且仅满足oneOf数组中的一个Schema | |
not | 它告诉Json不能满足not所对应的Schema |
需要注意,使用allOf时,Schema不论在内嵌的Schema里还是外部的Schema里,都不应该使"additionalProperties"为false。否则可能会生成任何数据都无法满足的矛盾Schema。
非json格式数据转化(New in draft 7)
{
"type": "string",
"contentEncoding": "base64",
"contentMediaType": "image/png"
}
if then else
{
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"country": {
"enum": ["United States of America", "Canada"]
}
},
"if": {
"properties": { "country": { "const": "United States of America" } }
},
"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 then实现了 allOf 等同于 oneOf
{
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"country": {
"enum": ["United States of America", "Canada", "Netherlands"]
}
},
"allOf": [
{
"if": {
"properties": { "country": { "const": "United States of America" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
}
},
{
"if": {
"properties": { "country": { "const": "Canada" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
}
},
{
"if": {
"properties": { "country": { "const": "Netherlands" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[0-9]{4} [A-Z]{2}" } }
}
}
]
}