JSON schema(模式)
JSON Schema 是一个描述和验证 JSON 数据结构的强大工具,我们可以把 JSON Schema 看作是一种规范,这个规范中规定了 JSON 数据的结构、键的命名、值的类型等等,通过规范可以校验指定的 JSON 数据,保证数据的准确。所以在接口调试过程中,经常使用 JSON Schema 来校验接口数据的准确性。
JSON Schema 就是为了解决上述问题诞生的,在 JSON Schema 中可以规定要在 JSON 中出现的字段、字段含义、字段类型等信息,而且可以使用 JSON Schema 来校验 JSON 数据是否符合 Schema 中定义的规范。
下面就是一个符合上面 Schema 的 JSON 数据:
如下例所示:
如果要引用另外的 Schema 文件,可以向下面这样:
例如我们要引用 http://c.biancheng.net/ 域名的某个 Schema,则可以将 $id 设置为下面这样:
除了可以使用第三方库外,还可以通过一些在线工具来使用 Schema,例如 https://jsonschemalint.com/#!/version/draft-04/markup/json。
什么是 JSON Schema
JSON Schema 译为“JSON模式”,它是由 IETF 编写和起草的。那么 JSON Schema 有什么作用呢?IETF 是 The Internet Engineering Task Force 的简称,译为“国际互联网工程任务组”,是一个公开性质的大型民间国际团体。
假如我们要使用 JSON 来存储一个产品的信息,如下所示:{ "id": 1, "name": "JSON教程", "author": "C语言中文网", "price": 99.9 }如上所示,虽然只是一段很简单的 JSON 数据,但是有人可能会问:“id”代表什么意思、“name”字段是否可以省略、“price”字段的值是否可以为 0 等等。
JSON Schema 就是为了解决上述问题诞生的,在 JSON Schema 中可以规定要在 JSON 中出现的字段、字段含义、字段类型等信息,而且可以使用 JSON Schema 来校验 JSON 数据是否符合 Schema 中定义的规范。
定义 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 数据必须符合以下要求:
- 类型为 object;
-
JSON 中可以包含以下四个键:
- name:必须是字符串类型;
- email:必须是字符串类型;
- age:必须是大于 0 的整数;
- telephone:必须是字符串类型,并且需要匹配指定的正则表达式。
- 上面的四个键中,name 和 email 必须定义,而 age 和 telephone 则是可选的;
- 除了上面四个键,不允许出现其它的键。
下面就是一个符合上面 Schema 的 JSON 数据:
{ "name": "C语言中文网", "email": "2758010091@qq.com", "age": 18 }大家都知道 JSON 中支持 string、number、object、array、boolean、null 等几种类型,针对不同的类型,Schema 中提供了一系列关键字,下面我们来介绍一下这些关键字以及用法:
1) 字符串(String)
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":正则表达式 |
2) 数值类型
JSON Schema 中有关数值的关键字如下表所示:关键字 | 描述 | 示例 |
---|---|---|
integer | 整数 | {"type": "integer"} |
number | 数字,包括整数和浮点数 | {"type": "number"} |
multipleOf | 数字必须是给定数字(正数)的倍数 | {"type": "number", "multipleOf": 3} |
minimum | 数值允许的最小值 | {"type": "number", "minimum": 1} |
maximum | 数值允许的最大值 | {"type": "number", "maximum": 9} |
3) 对象
属性(Properties)
在 JSON Schema 中,您可以使用 properties 关键字来定义 JSON 数据中的键,如下例所示:{ "type": "object", "properties": { "name": { "type": "string"}, "age": {"type": "number", "multipleOf": 3}, "date": { "type": "string", "format": "date" } } }
额外属性(Asdditional Properties)
在 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"} }
必须属性(Required Properties)
在 JSON Schema 中,您可以使用 required 关键字声明 JSON 中必须定义的键,required 的值为一个数组,数组中的每个值必须是唯一的,如下例所示:{ "type": "object", "properties": { "name": { "type": "string" }, "email": { "type": "string" }, "address": { "type": "string" }, "telephone": { "type": "string" } }, "required": ["name", "email"] }
属性名称(Property names)
在 JSON Schema 中,您可以使用 propertyNames 定义 JSON 数据中键的命名规则,如下例所示:{ "type": "object", "propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }
属性个数(Size)
在 JSON Schema 中,您可以使用 minProperties(最小数量)和 maxProperties(最大数量)关键字来限制 JSON 对象中键的个数,如下例所示:{ "type": "object", "minProperties": 2, "maxProperties": 3 }
4) 数组
数组是值的有序集合,JSON 数组中的每个值都可以是不同的类型。元素(items)
默认情况下,数组的值可以是任何类型,但在 JSON Schema 中可以使用 items、additionalItems 和 contains 关键字来验证数组中的值,对于 JSON 中的数组,通常有两种验证方式:- 列表验证(List validation):任意长度的数组,数组中每个值都匹配相同的 Schema;
- 元组验证(Tuple validation):固定长度的数组,数组中每个值可以匹配不同的 Schema。
列表验证(List validation)
若希望数组中每个值都匹配相同的模式,可以通过 items 关键字设置单个模式,来验证数组中的所有值。当使用单个模式时,additionalItems 关键字是无效的,如下例所示(验证数组的所有值为数字):{ "type": "array", "items": { "type": "number" } }contains 关键字仅需要针对数组中的一个或多个项目进行验证,如下例所示(只需包含至少一个数字元素):
{ "type": "array", "contains": { "type": "number" } }
元组验证(Tuple validation)
在 JSON 数据中,如果数组的每个值都有不同的含义,那么这些值的类型也可能是不同的,例如:[编号, 街道名称, 街道类型, 方向]
为此,在 Schema 中我们可以向下面这样来验证 JSON 数据:{ "type": "array", "items": [ { "type": "number" }, { "type": "string" }, { "type": "string", "enum": ["Street", "Avenue", "Boulevard"] }, { "type": "string", "enum": ["NW", "NE", "SW", "SE"] } ] }
数组长度(Length)
可以使用 minItems、 maxItems 关键字指定数组的长度。如下例所示(指定数组的长度范围为 2 ~ 3):{ "type": "array", "minItems": 2, "maxItems": 3 }
注意:数组长度不能为负数。
唯一(Uniqueness)
将 uniqueItems 关键字设置为 true 可以确保数组中的每个元素都是唯一的,如下例所示:{ "type": "array", "uniqueItems": true }
5) 布尔(boolean)
布尔类型只有两个值:true 和 false,如下例所示:{"type": "boolean"}
6) 空值(null)
空类型通常用于表示没有值,当将值的类型指定为 null 时,则表示它只有一个可接受的值——null,如下例所示:{"type": "null"}
7) 通用关键字
JSON Schema 包括几个通用的关键字 title、description、default、examples 用于不严格验证,这些关键字主要用来描述模式的功能、作用。这些注释属性都不是必须的,但建议添加。
- title 和 description 关键字必须是字符串,“title”最好比较简短,而“description”应该提供关于该 schema 的详细描述;
- default 关键字用来定义默认值;
- examples 关键字是用于提供一系列针对该模式进行验证的示例。
如下例所示:
{ "title": "Match anything", "description": "This is a schema that matches anything.", "default": "Default value", "examples": ["Anything", 4035] }
注释(Comments)
$comment 关键字用于添加注释/批注,它的值必须是一个字符串。枚举值(Enumerated values)
enum 关键字被用于定义枚举值(一组固定的值),它必须是一个至少包含一个值的数组,而且每个值都必须是唯一的。此外,type 和 enum 是并列的,必须同时满足,如下例所示:{ "type": "string", "enum": ["red", "amber", "green"] }
常量值(Constant values)
const 关键字被用于定义一个常量值,如下例所示:{ "properties": { "country": { "const": "United States of America" } } }const 是 enum 的语法糖,所以下面两个定义是等价的:
{ "const": "United States of America" } { "enum": [ "United States of America" ]}
8) $schema 关键字
$schema 关键字用于声明 JSON Schema 的版本,建议所有 JSON Schema 都声明一个 $schema,并且应该是 Schema 的第一个键/值对,如下例所示:{"$schema": "http://json-schema.org/draft-04/schema#"}如果需要声明 JSON Schema 的指定版本,则可以将 $schema 的值设置为以下几个:
- http://json-schema.org/draft-07/schema#
- http://json-schema.org/draft-06/schema#
- http://json-schema.org/draft-04/schema#
9) $ref 关键字
$ref 关键字用于引用其他地方的一个 Schema 片段,它的值为一个 URI 引用。如果是引用同一文档的 Schema 片段,则 $ref 的值需要以井号(#)开头,例如:{ "$ref": "#/definitions/address" }
上面示例中的“#/definitions/address”意味着:- 转到文档的根;
- 找到 "definitions" 键的值;
- 在该对象中,找到键 "address" 的值。
如果要引用另外的 Schema 文件,可以向下面这样:
{ "$ref": "definitions.json#/address" }
完整的示例如下所示:{ "$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" } } }
10) $id 关键字
$id 关键字的值是一个 URI 引用,它有两个用途:- 为 Schema 声明一个唯一的标识符;
- 声明一个基本 URI,$ref 可以基于该 URI 进行引用。
例如我们要引用 http://c.biancheng.net/ 域名的某个 Schema,则可以将 $id 设置为下面这样:
{ "$id": "http://c.biancheng.net/schemas/address.json" }
注意,当定义了上面所示的 $id 之后,若我们要使用 $ref 来引用同域名下的其它 Schema,则可以简写成如下所示的样子:{ "$ref": "person.json" }
使用 JSON Schema 进行验证
了解了 JSON Schema 之后,我们就可以使用它来校验 JSON 数据了。网络中有许多 JSON Schema 的库,您可以在 JSON Schema 的官网查找合适的库。除了可以使用第三方库外,还可以通过一些在线工具来使用 Schema,例如 https://jsonschemalint.com/#!/version/draft-04/markup/json。