JSON Schema 是一个描述和验证 JSON 数据结构的强大工具,我们可以把 JSON Schema 看作是一种规范,这个规范中规定了 JSON 数据的结构、键的命名、值的类型等等,通过规范可以校验指定的 JSON 数据,保证数据的准确。所以在接口调试过程中,经常使用 JSON Schema 来校验接口数据的准确性。
JSON Schema 译为“JSON模式”,它是由 IETF 编写和起草的。那么 JSON Schema 有什么作用呢?
假如我们要使用 JSON 来存储一个产品的信息,如下所示:
{
"id": 1,
"name": "JSON教程",
"author": "城东书院",
"price": 99.9
}
如上所示,虽然只是一段很简单的 JSON 数据,但是有人可能会问:“id”代表什么意思、“name”字段是否可以省略、“price”字段的值是否可以为 0 等等。
JSON Schema 就是为了解决上述问题诞生的,在 JSON Schema 中可以规定要在 JSON 中出现的字段、字段含义、字段类型等信息,而且可以使用 JSON Schema 来校验 JSON 数据是否符合 Schema 中定义的规范。
JSON Schema 本身是一段 JSON 格式的数据,如下例所示:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"age": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": false
},
"telephone": {
"type": "string",
"pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
}
},
"required": ["name", "email"],
"additionalProperties": false
}
上面 Schema 中,要求 JSON 数据必须符合以下要求:
下面就是一个符合上面 Schema 的 JSON 数据:
{
"name": "城东书院",
"email": "services@cdsy.xyz",
"age": 3
}
大家都知道 JSON 中支持 string、number、object、array、boolean、null 等几种类型,针对不同的类型,Schema 中提供了一系列关键字,下面我们来介绍一下这些关键字以及用法:
JSON Schema 中有关字符串的关键字如下表所示:
关键字 | 描述 | 可选值 |
---|---|---|
minLength | 字符串最小长度,不能为负数 | |
maxLength | 字符串最大长度,不能为负数 | |
pattern | 正则表达式 | |
format | 字符串格式 | "date-time":日期和时间,如 2018-11-13T20:20:39+00:00 "time":时间,如 20:20:39+00:00 "date":日期,如 2018-11-13 "email":电子邮箱地址 "hostname":主机名 "ipv4":IPv4 地址 "ipv6":IPv6 地址 "uri":通用资源标识符(URI) "uri-template":URI 模板(任何级别) "regex":正则表达式 |
JSON Schema 中有关数值的关键字如下表所示:
关键字 | 描述 | 示例 |
---|---|---|
integer | 整数 | {"type": "integer"} |
number | 数字,包括整数和浮点数 | {"type": "number"} |
multipleOf | 数字必须是给定数字(正数)的倍数 | {"type": "number", "multipleOf": 3} |
minimum | 数值允许的最小值 | {"type": "number", "minimum": 1} |
maximum | 数值允许的最大值 | {"type": "number", "maximum": 9} |
在 JSON Schema 中,您可以使用 properties 关键字来定义 JSON 数据中的键,如下例所示:
{
"type": "object",
"properties": {
"name": { "type": "string"},
"age": {"type": "number", "multipleOf": 3},
"date": {
"type": "string",
"format": "date"
}
}
}
在 JSON Schema 中,您可以使用 additionalPropertiesis 定义额外的属性,值为 false 或一个 Schema 对象,如下例所示
{
"type": "object",
"properties": {
"number": { "type": "number"},
"street_name": { "type": "string"},
"street_type": {
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
}
},
"additionalProperties": { "type": "string"}
}
在 JSON Schema 中,您可以使用 required 关键字声明 JSON 中必须定义的键,required 的值为一个数组,数组中的每个值必须是唯一的,如下例所示:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"address": { "type": "string" },
"telephone": { "type": "string" }
},
"required": ["name", "email"]
}
在 JSON Schema 中,您可以使用 propertyNames 定义 JSON 数据中键的命名规则,如下例所示:
{
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
}
}
在 JSON Schema 中,您可以使用 minProperties(最小数量)和 maxProperties(最大数量)关键字来限制 JSON 对象中键的个数,如下例所示:
{
"type": "object",
"minProperties": 2,
"maxProperties": 3
}
数组是值的有序集合,JSON 数组中的每个值都可以是不同的类型。
默认情况下,数组的值可以是任何类型,但在 JSON Schema 中可以使用 items、additionalItems 和 contains 关键字来验证数组中的值,对于 JSON 中的数组,通常有两种验证方式:
若希望数组中每个值都匹配相同的模式,可以通过 items 关键字设置单个模式,来验证数组中的所有值。当使用单个模式时,additionalItems 关键字是无效的,如下例所示(验证数组的所有值为数字):
{
"type": "array",
"items": {
"type": "number"
}
}
contains 关键字仅需要针对数组中的一个或多个项目进行验证,如下例所示(只需包含至少一个数字元素):
{
"type": "array",
"contains": {
"type": "number"
}
}
在 JSON 数据中,如果数组的每个值都有不同的含义,那么这些值的类型也可能是不同的,例如:
为此,在 Schema 中我们可以向下面这样来验证 JSON 数据:
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "string"
},
{
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
},
{
"type": "string",
"enum": ["NW", "NE", "SW", "SE"]
}
]
}
可以使用 minItems、 maxItems 关键字指定数组的长度。如下例所示(指定数组的长度范围为 2 ~ 3):
{
"type": "array",
"minItems": 2,
"maxItems": 3
}
注意:数组长度不能为负数。
将 uniqueItems 关键字设置为 true 可以确保数组中的每个元素都是唯一的,如下例所示:
{
"type": "array",
"uniqueItems": true
}
布尔类型只有两个值:true 和 false,如下例所示:
{"type": "boolean"}
空类型通常用于表示没有值,当将值的类型指定为 null 时,则表示它只有一个可接受的值——null,如下例所示:
{"type": "null"}
JSON Schema 包括几个通用的关键字 title、description、default、examples 用于不严格验证,这些关键字主要用来描述模式的功能、作用。这些注释属性都不是必须的,但建议添加。
如下例所示:
{
"title": "Match anything",
"description": "This is a schema that matches anything.",
"default": "Default value",
"examples": ["Anything", 4035]
}
$comment 关键字用于添加注释/批注,它的值必须是一个字符串。
enum 关键字被用于定义枚举值(一组固定的值),它必须是一个至少包含一个值的数组,而且每个值都必须是唯一的。此外,type 和 enum 是并列的,必须同时满足,如下例所示:
{
"type": "string",
"enum": ["red", "amber", "green"]
}
const 关键字被用于定义一个常量值,如下例所示:
{
"properties": {
"country": {
"const": "United States of America"
}
}
}
const 是 enum 的语法糖,所以下面两个定义是等价的:
{ "const": "United States of America" }
{ "enum": [ "United States of America" ]}
$schema 关键字用于声明 JSON Schema 的版本,建议所有 JSON Schema 都声明一个 $schema,并且应该是 Schema 的第一个键/值对,如下例所示:
{"$schema": "http://json-schema.org/draft-04/schema#"}
如果需要声明 JSON Schema 的指定版本,则可以将 $schema 的值设置为以下几个:
$ref 关键字用于引用其他地方的一个 Schema 片段,它的值为一个 URI 引用。如果是引用同一文档的 Schema 片段,则 $ref 的值需要以井号(#)开头,例如:
上面示例中的“#/definitions/address”意味着:
如果要引用另外的 Schema 文件,可以向下面这样:
完整的示例如下所示:
{
"$schema": "http://json-schema.org/draft-04/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 关键字也可以引用当前 Schema 中的某一部分(类似于编程中的递归)。例如您有一个 person 模式,其中包含一个数组 children,每个数组也是一个 person 实例,如下例所示:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"person": {
"type": "object",
"properties": {
"name": { "type": "string" },
"children": {
"type": "array",
"items": { "$ref": "#/definitions/person" },
"default": []
}
}
}
},
"type": "object",
"properties": {
"person": { "$ref": "#/definitions/person" }
}
}
$id 关键字的值是一个 URI 引用,它有两个用途:
例如我们要引用 http://www.cdsy.xyz/ 域名的某个 Schema,则可以将 $id 设置为下面这样:
注意,当定义了上面所示的 $id 之后,若我们要使用 $ref 来引用同域名下的其它 Schema,则可以简写成如下所示的样子:
了解了 JSON Schema 之后,我们就可以使用它来校验 JSON 数据了。网络中有许多 JSON Schema 的库,您可以在 JSON Schema 的官网查找合适的库。
除了可以使用第三方库外,还可以通过一些在线工具来使用 Schema,例如 https://jsonschemalint.com/#!/version/draft-04/markup/json。