这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
在实际业务中,后端存在某些参数极为复杂的接口,这时候可以把所有的参数都用JSON接收。但是,JSON校验就成了一个棘手的问题,手写校验复杂且繁琐。
任何数据都可能有两个验证阶段:
架构级别:json结构可以通过JSON Schema验证语义级别:json的语义需要转换成实际的业务实体来进行校验
而JSON Schema 是用于验证 JSON 数据结构的强大工具,通过它可以快速验证复杂的JSON结构。JSON Schema本身是用JSON编写的,用于“描述其他数据结构”的声明性格式。
一、基本
1. 相关概念
-
JSON实例:表示数据模型解释文档,根据JSON Schema解释的 JSON 值称为“实例”;用JSON的话说就是
value格式、取值相同- JSON实例相等:当且仅当两个 JSON 实例属于相同类型且具有相同值时,才称它们相等;
- 可以将 JSON Schema 与 JSON Schema 数据模型的超集一起使用,其中实例可能在六种 JSON 数据类型中的任何一种之外。
-
JSON Schema:JSON Schema 文档,或简称为 schema,是定义JSON元数据的JSON 文档;JSON元数据通过关键字(keyword)定义了Json数据需要满足的规范,规范包括了
成员、结构、类型、约束等
注:对象必须具有相同数量的成员,对象中的属性是无序的,无法定义多个具有相同KEY的属性,而仅仅是格式上的差异(缩进、放置逗号、尾随零)无关紧要。
注2:由于一个对象不能有两个具有相同键的属性,因此尝试在单个对象中定义具有相同键的两个属性的 JSON 文档的行为是undefined的。
注3:模式本身可以被解释为一个实例,但应该总是被赋予媒体类型“application/schema+json”而不是“application/schema-instance+json”。“application/schema+json”媒体类型被定义为提供“application/schema-instance+json”提供的片段标识符语法和语义的超集。
2. JSON Schema Documents的组成
-
JSON关键字:应用于实例的对象属性称为关键字或模式关键字
- identifiers(身份标志):URI
- assertions(断言):应用于实例,判断状态,产生布尔类型结果
- annotations(注释)
- applicators:将一个或多个子模式应用于实例中的特定位置,并组合或修改它们的结果
- reserved locations:不直接影响结果,但为特定目的预留位置以确保互操作性
-
Boolean JSON Schemas:用于阐明模式作者的意图并促进模式处理优化
- true:表示空模式{}
- false:表示模式{ "not": {} }
-
Schema Vocabularies:模式词汇表,或简称为词汇表,是一组关键字、语法和语义;
- 定义词汇表通常是为了特定目的组织起来的;
- 可以定义词汇表是必需或可选的
-
Meta-Schemas(元模式):用于描述模式的模式,用于验证JSON模式并指定使用的词汇表
-
Root Schema and Subschemas and Resources(根模式、子模式和资源)
例如:
{
"title": "root", // 文档的根模式
"items": { // 包含子模式
"title": "array item"
}
}
二、关键字
Json Schema中的常用的关键字可以分为类型关键字、通用关键字以及schema组合
1. 类型关键字
string
相关属性:
- minLength
- maxLength
- pattern
- format
- Dates and times(日期和时间)
- "date-time":例如 2018-11-13T20:20:39+00:00
- "time":例如 20:20:39+00:00
- "date":例如 2018-11-13
- Email addresses(邮箱地址)
- "email"
- "idn-email"
- Hostnames(host)
- "hostname"
- "idn-hostname"
- IP Addresses(IP地址)
- "ipv4"
- "ipv6"
- Resource identifiers(绝对或相对资源路径)
- "uri"
- "uri-reference"
- "iri"
- "iri-reference"
- URI template
- "uri-template"
- JSON Pointer(json schema 快捷链接)
- "json-pointer"
- "relative-json-pointer"
- Regular Expressions(正则)
- "regex"
- Dates and times(日期和时间)
number
- multipleOf 将数字限定为该属性的倍数,可以为任何整数
- Range(设置范围):
minimum、exclusiveMinimum、maximum、exclusiveMaximum- x ≥ minimum
- x > exclusiveMinimum
- x ≤ maximum
- x < exclusiveMaximum
例如:
{
"type": "number",
"minimum": 0,
"maximum": 100,
"exclusiveMaximum": true
}
integer (只能表示整数)
object(JSON映射类型)
- properties(属性键值对)
- key 属性名称
- value 对象
- patternProperties (如果属性名匹配模式,属性值必须通过特定schema的验证)
- additionalProperties 默认为true,设置为false表示不允许额外的属性
- required 定义必须的字段
- propertyNames 验证属性名
- minProperties 限制至少有几个属性
- maxProperties 限制最多有几个属性
例如:
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
"street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
}
}
{
"type": "object",
"patternProperties": {
"^S_": { "type": "string" },
"^I_": { "type": "integer" }
}
}
// 允许类型为string的额外属性
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
"street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
},
"additionalProperties": { "type": "string" }
}
{
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
}
}
//ERR
{
"001 invalid": "value"
}
array
- items
- 列表:存放同种类型数据
- 元组:存放不同类型数据
- additionalItems:默认为true,允许额外类型的项;如果不是元组,则忽略该属性
- contains:该属性表示包含某种类型即可
- minItems
- maxItems
- uniqueItems 用于保证item唯一
例如:
// 列表
{
"type": "array",
"items": {
"type": "number"
}
}
// 元组
{
"type": "array",
"items": [
{ "type": "number" },
{ "type": "string" },
{ "enum": ["Street", "Avenue", "Boulevard"] },
{ "enum": ["NW", "NE", "SW", "SE"] }
]
}
boolean
布尔类型只匹配两个特殊值:true和false。请注意,架构不接受判定其余值为true或false,例如1和0的值。
null
- 当架构指定空缺类型时,它只有一个可接受的值:null
- 在json中,null不等同于不存在的东西
2. 通用关键字
JSON Schema包含一些关键字不用于验证,而是用于描述模式;编写JSON Schema的开发人员不一定需要这些“注释”关键字,但鼓励使用这些字段使架构能“自我记录”。
- title 标题
- description 描述
- default 表示默认值
- examples 示例JSON
- readOnly 表示不应修改值
- writeOnly 表示可以设置值
- $comment 表示注释
- enum 表示枚举
- const 常量、限制为单个值
{
"title": "Match anything",
"description": "This is a schema that matches anything.",
"default": "Default value",
"examples": [
"Anything",
4035
],
"readOnly": true,
"writeOnly": false
}
{
"enum": ["red", "amber", "green"]
}
3. Schema 组合
- allOf(AND):所有条件都对子模式有效、非空数组,每一项都是有效的JSON Schema
- anyOf(OR):至少有一个条件对子模式有效、非空数组
- oneOf(XOR):有且只有一个条件对子模式有效、非空数组
- not(NOT):所有的都不匹配则表示成功
{
"allOf": [
{ "type": "string" },
{ "maxLength": 5 }
]
}
"short" TRUE
"too long" FALSE
{
"anyOf": [
{ "type": "string", "maxLength": 5 },
{ "type": "number", "minimum": 0 }
]
}
"short" TRUE
"too long" FALSE
12 TRUE
-5 FALSE
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
10 TRUE
9 TRUE
2 FALSE
15 FALSE
{ "not": { "type": "string" } }
42 TRUE
{ "key": "value" } TRUE
"I am a string" FALSE
注:allOf不允许使用additionalProperties
分解模式:子模式的公共部分支持分解,以下的两个模式等效
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
{
"type": "number",
"oneOf": [
{ "multipleOf": 5 },
{ "multipleOf": 3 }
]
}