使用JSON Schema进行参数验证

什么是 JSON Schema

JSON Schema 是基于 JSON 语法,用来描述 JSON 数据格式的一种规范。可以数据校验、生成接口文档,生成模拟数据等多种用途。

本质上,JSON 是由以下几种基本的数据结构组成的:

  • 对象 objects
  • 数组 array
  • 数字 number
  • 字符串 string
  • 布尔值 boolean
  • null

JSON Schema 对这些类型都做了规定。同时,JSON Schema 的规范也在不断的迭代更新,下文讲解基于 Draft 4。

公共属性

常用

  • type 定义数据类型;
  • enum 定义可取值列表;
  • default 定义默认值,默认值虽然有定义,但是不强制要求实现;

元数据

  • title 标题(可选)
  • description 描述(可选)
  • $schema 声明这是一个 schema,值一般为 http://json-schema.org/schema#,也可以为一个指向官网草案版本的链接,例如:http://json-schema.org/draft-06/schema#

组合验证属性

  • anyOf 传一个 schema 列表,只要满足其中一个就验证通过。
  • allOf 传一个 schema 列表,必须满足其中全部才能验证通过。
  • oneOf 传一个 schema 列表,仅仅满足其中一个时才验证通过。
  • not 传一个 schema,不满足时会验证通过。

验证

验证 all

当 JSON Schema 为空时,任意内容都能通过验证

1
{ }

验证 string

1
{"type": "string"}

附加参数有:

  • minLength 规定最小长度
  • maxLength 规定最大长度
  • pattern 正则表达式,建议使用 ^…$ 进行整行匹配;
  • format 草案中规定的一些内置的格式,不强制要求实现;

验证 number

number 有两种细分类型: integer 和 number

integer

用于验证整型

1
{"type": "integer"}

number

1
{"type": "number"}

附加参数有:

  • multipleOf 被验证值必须是该值的倍数,该值必须是正数。
  • minimum 最小值
  • exclusiveMinimum 传 bool 参数,最小值是否不包含边界值,默认包含,即 false
  • maximum 最大值
  • exclusiveMaximum 传 bool 参数,最大值是否不包含边界值,默认包含,即 false

边界值参数 Draft 6 和 Draft 4 有很大不同。

验证 object

1
2
3
4
5
6
7
8
9
10
11
{
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"gender": {
"type": "string",
"enum": ["male", "female"]
}
}
}

默认情况下,object 中不传某个属性或者多传某个属性都能够验证通过。因此上述 Schema 对 {} 也能验证通过。

附加参数:

  • properties 定义属性
  • additionalProperties
    • True:允许附加属性
    • False:不允许附加属性
    • object:规定附加属性验证,例如 "additionalProperties": { "type": "string" } 规定附加属性必须是字符串。
  • required 一个元素唯一的非空列表(Draft 6 允许为空),规定必传参数;
  • minProperties
  • maxProperties
  • dependencies
    • 属性依赖,例如 "dependencies": {"credit_card": ["billing_address"]}表示,拥有 credit_card 属性时必须拥有 billing_address 属性;
    • Schema 依赖,能够定义依赖变量的类型等,相当于内嵌 schema。
  • patternProperties 使用正则定义的属性列表。可以与 additionalProperties 配合使用,additionalProperties 只定义不希望被正则匹配的属性。

一个 Schema 依赖的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"type": "object",
"properties": {
"credit_card": {"type": "number"},
"name": {"type": "string"}
},
"dependencies": {
"credit_card": {
"properties": {
"billing_address": {"type": "string"}
},
"required": ["billing_address"]
}
},
"required": ["name"]
}

一个 patternProperties 的例子:

1
2
3
4
5
6
7
8
{
"additionalProperties": false,
"patternProperties": {
"^I_": {"type": "integer"},
"^S_": {"type": "string"}
},
"type": "object"
}

验证 array

1
{"type": "array"}

附加参数:

  • items
    • 用于 List validation 时值为 schema,所有元素都要满足验证条件,例如 'items': {‘type': 'number'} 要求所有元素都是数字类型;
    • 用于 Tuple validation 时值为 schema 组成的列表,根据元素顺序依次验证每个元素,可以少传或者多传元素都能验证通过;
  • additionalItems 在 Tuple validation 时可以定义额外元素的验证。
  • minItems
  • maxItems
  • uniqueItems 元素是否唯一

验证 boolean

1
{"type": "boolean"}

0 和 1,字符串 “True” 和 “False” 都不能验证通过。

验证 null

1
{"type": "null"}

复杂结构

Reuse

使用 $ref 可以在一个 schema 中引用另一个 schema,这样可以定义部分公共 schema,其他 schema 重用这部分公共 schema 即可,避免重复定义。

举例说明,下面的 schema 在 definitions 中对地址数据进行了描述,在定义其他地址时,可以应用该地址描述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"$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 取值可以是:

  • 同一 JSON Schema 文件中的定义,以 # 开头;
  • 相对路径 URI,例如 definitions.json#/address
  • 绝对路径 URI;

递归模式

$ref 元素可用于创建引用自身的递归模式。例如,一个 person 包含的 children 数组,每个 children 也是 person 实例。

但请注意,$ref 相互引用的模式可能会导致解析器中的无限循环,不应该这样做。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"$schema": "http://json-schema.org/draft-06/schema#",

"definitions": {
"person": {
"type": "object",
"properties": {
"name": { "type": "string" },
"children": {
"type": "array",
"items": { "$ref": "#/definitions/person" },
"default": []
}
}
}
},

"type": "object",

"properties": {
"person": { "$ref": "#/definitions/person" }
}
}

参考链接

觉得有用可以请作者喝杯咖啡呀~
0%