JSON Schema 介绍

JSON Schema 规范参考文档:JSON Schema 规范中文版JSON Schema 介绍 - 图1

一、如何描述 JSON ?

JSON (JavaScript Object Notation) 缩写,JSON 是一种数据格式,具有简洁、可读性高、支持广泛的特点。JSON 有以下基本数据类型

  1. // # 1. object
  2. { "key1": "value1", "key2": "value2" }
  3. // # 2. array
  4. [ "first", "second", "third" ]
  5. // # 3. number
  6. 42
  7. // # 4. string
  8. "This is a string"
  9. // # 5. boolean
  10. true
  11. false
  12. // # 6. null
  13. null

在其它语言中也有类似的内建数据类型,但是由于 JavaScript的广泛应用,而 JSON 作 为 JavaScript原生的数据类型,具备更加广泛的支持。

有了上面列举的基本数据类型,JSON 能非常灵活的表示任意复杂的数据结构。举个例子:

  1. {
  2. "name": "George Washington",
  3. "birthday": "February 22, 1732",
  4. "address": "Mount Vernon, Virginia, United States"
  5. }

如何描述上面 JSON 对象呢?

首先,它是一个 object

其次,它拥有 namebirthdayaddress 这三个字段

并且,nameaddress 的字段值是一个字符串 Stringbirthday 的值是一个日期。

最后,将上面的信息如何用 JSON 来表示?如下:

  1. {
  2. "type": "object",
  3. "properties": {
  4. "name": { "type": "string" },
  5. "birthday": { "type": "string", "format": "date" },
  6. "address": { "type": "string" }
  7. }
  8. }

这个表示就是一个 JSON SchemaJSON Schema 介绍 - 图2JSON SchemaJSON Schema 介绍 - 图3 用于描述 JSON 数据。

相同的数据,可能有不同的表示,比如下面的两种表示,包含的信息量基本是一致的:

  1. // # 1. 表示一
  2. {
  3. "name": "George Washington",
  4. "birthday": "February 22, 1732",
  5. "address": "Mount Vernon, Virginia, United States"
  6. }
  7. // # 2. 表示二
  8. {
  9. "first_name": "George",
  10. "last_name": "Washington",
  11. "birthday": "1732-02-22",
  12. "address": {
  13. "street_address": "3200 Mount Vernon Memorial Highway",
  14. "city": "Mount Vernon",
  15. "state": "Virginia",
  16. "country": "United States"
  17. }
  18. }

在特定的应用场景中,应用程序对数据的结构要求是确定的,出于对数据描述的规范化需 求,需要用 JSON SchemaJSON Schema 介绍 - 图4 来规范化。使用 JSON SchemaJSON Schema 介绍 - 图5 可以描述 JSON 数据所包含的字 段、以及字段值的类型,以及依赖关系等。

相同信息量的数据,采用不同的形式来表达,用 JSON SchemaJSON Schema 介绍 - 图6 来描述也是不一样的,表示二的 JSON Schema 如下:

  1. {
  2. "type": "object",
  3. "properties": {
  4. "first_name": { "type": "string" },
  5. "last_name": { "type": "string" },
  6. "birthday": { "type": "string", "format": "date-time" },
  7. "address": {
  8. "type": "object",
  9. "properties": {
  10. "street_address": { "type": "string" },
  11. "city": { "type": "string" },
  12. "state": { "type": "string" },
  13. "country": { "type" : "string" }
  14. }
  15. }
  16. }
  17. }

从上面的描述,可以很自然的想到 JSON SchemaJSON Schema 介绍 - 图7 可以用来做数据校验,比如前后端先把数 据接口约定好,写好 JSON SchemaJSON Schema 介绍 - 图8,等后端把接口输出完毕,直接用 JSON SchemaJSON Schema 介绍 - 图9 来对接 口做验收。

关于 JSON SchemaJSON Schema 介绍 - 图10 的应用,对 JSON SchemaJSON Schema 介绍 - 图11 有过了解的人可以直接跳到第三、四部分。

接下来对 JSON SchemaJSON Schema 介绍 - 图12 做一些举例说明。

二、JSON Schema 的举例

1. 空 schema

  1. {}

以下都是合法的 JSON

  1. 42
  2. "I'm a string"
  3. [{"an": "aaa","bbb":{"nest":"data"}}]

2. type 指定 JSON 数据类型

  1. { "type": "string" }
  2. "I'm a string"
  3. 42
  4. { "type": "number" }
  5. 42
  6. "42"
  7. type` 的可能取值: `string` 、`number` 、`object`、 `array`、 `boolean`、 `null

3. type 可以包含多个类型

  1. { "type": ["number", "string"] }
  2. "I'm a string" // 合法
  3. 42 // 合法
  4. ["Life", "the universe", "and everything"] // 不合法

4. string 限定长度

  1. {
  2. "type": "string",
  3. "minLength": 2,
  4. "maxLength": 3
  5. }
  6. "AA" // 合法
  7. "AAA" // 合法
  8. "A" // 不合法
  9. "AAAA" // 不合法

5. string 模式匹配

  1. {
  2. "type": "string",
  3. "pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
  4. }
  5. "555-1212" // ok
  6. "(888)555-1212" // ok
  7. "(888)555-1212 ext. 532" // not ok
  8. "(800)FLOWERS" // not ok

6. string 值的枚举

  1. {
  2. "type": "string",
  3. "enum": ["red", "amber", "green"]
  4. }
  5. "red" // ok
  6. "blue" // not ok: blue 没有在 enum 枚举项中

7. integer

integer 一定是整数类型的 number

  1. { "type": "integer" }
  2. 42 // ok
  3. 1024 // ok

8. multipleOf 数字倍数

  1. { "type": "number", "multipleOf": 2.0 }
  2. 42 // ok
  3. 21 // not ok

9. number 限定范围

  1. {
  2. "type": "number",
  3. "minimum": 0,
  4. "maximum": 100,
  5. "exclusiveMaximum": true
  6. }

exclusiveMaximumtrue 表示不包含边界值 maximum,类似的还有 exclusiveMinimum 字段.

10. object 不允许有额外的字段

  1. {
  2. "type": "object",
  3. "properties": {
  4. "number": { "type": "number" },
  5. "street_name": { "type": "string" },
  6. "street_type": {
  7. "type": "string",
  8. "enum": ["Street", "Avenue", "Boulevard"]
  9. }
  10. },
  11. "additionalProperties": false
  12. }
  13. { "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue" } // ok
  14. { "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue","direction": "NW" } // not ok

因为包含了额外的字段 direction,而 schema 规定了不允许额外的字段 "additionalProperties": false

11. object 允许有额外的字段,并限定类型

  1. {
  2. "type": "object",
  3. "properties": {
  4. "number": { "type": "number" },
  5. "street_name": { "type": "string" },
  6. "street_type": {
  7. "type": "string",
  8. "enum": ["Street", "Avenue", "Boulevard"]
  9. }
  10. },
  11. "additionalProperties": { "type": "string" }
  12. }
  13. { "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue","direction": "NW" } // ok
  14. { "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "office_number": 201 } // not ok
  15. 额外字段 `"office_number": 201` number 类型,不符合 schema

12. object 必填字段

  1. {
  2. "type": "object",
  3. "properties": {
  4. "name": { "type": "string" },
  5. "email": { "type": "string" },
  6. "address": { "type": "string" },
  7. "telephone": { "type": "string" }
  8. },
  9. "required": ["name", "email"]
  10. }
  11. // ok
  12. {
  13. "name": "William Shakespeare",
  14. "email": "bill@stratford-upon-avon.co.uk"
  15. }

多出字段也是 ok 的

  1. // ok
  2. {
  3. "name": "William Shakespeare",
  4. "email": "bill@stratford-upon-avon.co.uk",
  5. "address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
  6. "authorship": "in question"
  7. }

少了字段,就是不行

  1. // not ok
  2. {
  3. "name": "William Shakespeare",
  4. "address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
  5. }

13. object 指定属性个数

  1. {
  2. "type": "object",
  3. "minProperties": 2,
  4. "maxProperties": 3
  5. }
  6. { "a": 0, "b": 1 } // ok
  7. { "a": 0, "b": 1, "c": 2, "d": 3 } // not ok

14. Dependencies 依赖

  1. 略复杂,不提供示例

15. Object 属性的模式匹配

  1. {
  2. "type": "object",
  3. "patternProperties": {
  4. "^S_": { "type": "string" },
  5. "^I_": { "type": "integer" }
  6. },
  7. "additionalProperties": false
  8. }
  9. { "S_25": "This is a string" } // ok
  10. { "I_0": 42 } // ok
  11. // not ok
  12. { "I_42": "This is a string" }
  13. { "keyword": "value" }

16. array 数组

  1. // ok
  2. { "type": "array" }
  3. [1, 2, 3, 4, 5]
  4. [3, "different", { "types" : "of values" }]
  5. // not ok:
  6. {"Not": "an array"}

17. array 指定数组成员类型

  1. {
  2. "type": "array",
  3. "items": {
  4. "type": "number"
  5. }
  6. }
  7. [1, 2, 3, 4, 5] // ok
  8. [1, 2, "3", 4, 5] // not ok

18. array 指定数组成员类型,逐个指定

  1. {
  2. "type": "array",
  3. "items": [{
  4. "type": "number"
  5. },{
  6. "type": "string"
  7. },{
  8. "type": "string",
  9. "enum": ["Street", "Avenue", "Boulevard"]
  10. },{
  11. "type": "string",
  12. "enum": ["NW", "NE", "SW", "SE"]
  13. }]
  14. }
  15. // ok
  16. [1600, "Pennsylvania", "Avenue", "NW"]
  17. [10, "Downing", "Street"] // 缺失一个也是可以的
  18. [1600, "Pennsylvania", "Avenue", "NW", "Washington"] // 多出一个也是可以的
  19. // not ok
  20. [24, "Sussex", "Drive"]
  21. ["Palais de l'Élysée"]

19. array 指定数组成员类型,逐个指定,严格限定

  1. {
  2. "type": "array",
  3. "items": [{
  4. "type": "number"
  5. },
  6. {
  7. "type": "string"
  8. },
  9. {
  10. "type": "string",
  11. "enum": ["Street", "Avenue", "Boulevard"]
  12. },
  13. {
  14. "type": "string",
  15. "enum": ["NW", "NE", "SW", "SE"]
  16. }
  17. ],
  18. "additionalItems": false
  19. }
  20. [1600, "Pennsylvania", "Avenue", "NW"] // ok
  21. [1600, "Pennsylvania", "Avenue"] // ok
  22. [1600, "Pennsylvania", "Avenue", "NW", "Washington"] // not ok 多出了字段就是不行

20. array 数组长度限制

  1. {
  2. "type": "array",
  3. "minItems": 2,
  4. "maxItems": 3
  5. }
  6. [1, 2] // ok
  7. [1, 2, 3, 4] // not ok

21. array element uniqueness 数组元素的唯一性

  1. {
  2. "type": "array",
  3. "uniqueItems": true
  4. }
  5. [1, 2, 3, 4, 5] // ok
  6. [1, 2, 3, 3, 4] // not ok:出现了重复的元素 3

22. boolean

  1. { "type": "boolean" }
  2. true // ok
  3. 0 // not ok

23. null

  1. { "type": "null" }
  2. null // ok
  3. "" // not ok

24. schema 的合并

string 类型,最大长度为 5 ;或 number 类型,最小值为 0

  1. {
  2. "anyOf": [
  3. { "type": "string", "maxLength": 5 },
  4. { "type": "number", "minimum": 0 }
  5. ]
  6. }
  7. `anyOf` 包含了两条规则,符合任意一条即可
  8. "short" // ok
  9. 42 // ok
  10. "too long" // not ok 长度超过 5
  11. -5 // not ok 小于了 0

25. allOf、oneOf

  1. `anyOf` 是满足任意一个 Schema 即可,而 `allOf` 是要满足所有 Schema
  2. `oneOf` 是满足且只满足一个

26. oneOf

  1. {
  2. "oneOf": [
  3. { "type": "number", "multipleOf": 5 },
  4. { "type": "number", "multipleOf": 3 }
  5. ]
  6. }
  7. 10 // ok
  8. 15 // not ok 因为它既是 3 又是 5 的倍数

上面的 schema 也可以写为:

  1. {
  2. "type": "number",
  3. "oneOf": [
  4. { "multipleOf": 5 },
  5. { "multipleOf": 3 }
  6. ]
  7. }

27. not

  1. { "not": { "type": "string" } }

只要是非 string 类型即可

  1. 42 // ok
  2. {"key" : "value"} // ok
  3. "This is a string" // not ok