[TOC]
前言:什么是JSON Schema
JSON Schema
,也称为JSON模式
。JSON Schema
是描述你的JSON
数据格式;
主要有以下作用:
- 对现有的
JSON
数据格式进行描述(字段类型、内容长度、是否必须存在、取值示例等); - 是一个描述清晰、人机可读的文档;
- 自动测试、验证客户端提交的数据;
简单示例
把需要被验证的JSON
文档称为instance
,用来校验它的文档就是schema
;
需要被校验的instance
:
{
"productId": 1,
"productName": "A green door",
"price": 12.50,
"tags": [ "home", "green" ]
}
用来校验它的schema
:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer" // productId为整形类型
},
"productName": {
"description": "Name of the product",
"type": "string" // productName为字符串类型
},
"price": {
"description": "The price of the product",
"type": "number", // price的值为任意数字类型
"exclusiveMinimum": 0 // price的值应该大于0
},
"tags": {
"description": "Tags for the product",
"type": "array", // TAG为数组类型
"items": {
"type": "string" // TAG的值为字符串类型
},
"minItems": 1, // 至少包含一个TAG
"uniqueItems": true // TAG不重复
}
},
"required": [ "productId", "productName", "price" ] // 必需字段:productId, productName, price,意味着tag可以忽略
}
1. JSON Schema 关键字
关键字 | 描述 |
---|---|
$schema | 指定 Json Schema版本,不同版本间不完全兼容,可省略 |
title | 用于进行简单的描述,可以省略 |
description | 用于进行详细的描述信息,可以省略 |
type | 用于约束 json 的字段类型,其值可以是:null、string、number、integer、object、array、boolean |
properties | 定义属性字段,定义每个字段的键和值类型 |
2. JSON Schema类型
任意对象
对于任意对象实例都可以使用type
,enum
和const
关键字。
关键字 | 描述 |
---|---|
type | 用于约束该实例的类型,其值可以是:null、string、number、integer、object、array、boolean |
emun | 该值应该是一个去重的数组,且至少包含一个元素(元素可以是任意类型包含null),代表该字段取值应该属于该数组中 |
const | 该值可以是任意类型甚至null,等效于enum且只有一个元素的情况 |
object
对象类型主要有三个关键字:type
限定类型,properties
定义对象中的各个字段,required
限定必需字段。
关键字 | 描述 |
---|---|
properties | 定义属性字段,定义每个字段的键和值类型 |
type | 用于约束 json 的字段类型,其值可以是:null、string、number、integer、object、array、boolean |
required(dependentRequired) | 必需属性,数组类型,指定上述 properties 中哪些是必需的字段 |
maxProperties | 最大属性个数 |
minProperties | 最小属性个数 |
additionalProperties | 将用于验证与 properties 不匹配的属性是否被允许 |
patternProperties | 将正则表达式映射到模式。如果属性名称与给定的正则表达式匹配,则属性值必须符合定义的类型 |
举例:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/root.json",
"title": "The Root Schema",
"description":"test",
"type": "object",
"required": [
"foo",
"bar",
],
"properties": {
"foo": {
"type": "number"
},
"bar": {
"const": "Must equal this value"
}
}
}
更多查阅:Object
Array
列表验证对于任意长度的数组非常有用,其中每个项都匹配相同的模式。
关键字 | 描述 |
---|---|
items | 值被定义成一个独立的校验对象,可以包含对应的字段属性。例如:type,如果是object还能添加properties |
maxItems | 数组最大的元素个数 |
minItems | 数组最小的元素个数 |
uniqueItems | type 为 array 时,数组元素是否唯一,如果唯一设置为true |
Contains | 包含模式,对数组中的一个或多个项进行验证 |
minContains / maxContains | 可以与contains一起使用,以进一步指定模式匹配包含约束的次数。这些关键字可以是任何非负数,包括零。 |
举例:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
使用prefixItems
数组还可以设置多个校验,用于数字值类型不固定的情况:
如果我们有这样一条数组数据:
1600 Pennsylvania Avenue NW
他们的类型为:
// number: 地址号,数字
// street_name: 街道名,字符串
// street_type: 街道类型,多个字符串中的一个也就是枚举
// direction:地址的城市方向,也是枚举。
[number, street_name, street_type, direction]
例子的schema为:
{
"type": "array",
"prefixItems": [
{ "type": "number" },
{ "type": "string" },
{ "enum": ["Street", "Avenue", "Boulevard"] },
{ "enum": ["NW", "NE", "SW", "SE"] }
]
}
但这个schema只能校验前4个值,如果我们的数组有了更多的值时:
[1600, "Pennsylvania", "Avenue", "NW", "Washington"]
此时schema应调整为:
{
"type": "array",
"items": { "type": "string" },
"prefixItems": [
{ "type": "number" },
{ "type": "string" },
{ "enum": ["Street", "Avenue", "Boulevard"] },
{ "enum": ["NW", "NE", "SW", "SE"] }
]
}
更多查阅:Array
String
关键字 | 描述 |
---|---|
maxLength | 数组最大的元素个数 |
minLength | 数组最小的元素个数 |
format | 允许对常用的某些类型的字符串值进行基本的语义标识,format只是一个注释,并不影响验证。 |
pattern | 用于将字符串限制为特定的正则表达式。 |
举例:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"ip": {
"type": "string",
"pattern": "w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*"
},
"host": {
"type": "phoneNumber",
"pattern": "((d{3,4})|d{3,4}-)?d{7,8}(-d{3})*"
},
},
"required": [
"ip",
"host"
]
}
Enum
枚举类型,允许校验对象和数组2种写法:
// 方式一,对象写法
{
"type": "object",
"properties": {
"street_type": {
"type": "string",
"enum": [
"Street",
"Avenue",
"Boulevard"
]
}
}
}
// 方式二,数组
{
"type": "object",
"properties": {
"street_type": [
"Street",
"Avenue",
"Boulevard"
]
}
}
Numeric
关键字 | 描述 |
---|---|
multipleOf | 是某数的倍数,必须大于0的整数 |
minimum | 对于数值x: x ≥ minimum
|
exclusiveMinimum | 对于数值x: x > exclusiveMinimum
|
maximum | 对于数值x: x ≤ maximum
|
exclusiveMaximum | 对于数值x: x < exclusiveMaximum
|
Integer
integer类型用于整型数。JSON对整数和浮点值没有不同的类型。因此,小数点的存在或不存在不足以区分整数和非整数。例如:1和1.0是在JSON中表示相同值的两种方法,JSON模式认为该值是整数。
Number
number 关键字可以描述任意长度,任意小数点的数字。
Boolean
布尔类型只匹配两个特殊值:true和false。
注意:不接受非true或false的值,例如1和0。
3. 模式构成
allOf
给定的数据必须对所有给定的子模式有效(AND操作)。
{
"allOf": [
{ "type": "string" },
{ "maxLength": 5 }
]
}
// "short" ==> ok
// "too long" ==> failed
anyOf
给定的数据必须对给定的任何(一个或多个)子模式有效(OR操作)。
{
"anyOf": [
{ "type": "string", "maxLength": 5 },
{ "type": "number", "minimum": 0 }
]
}
// "short" ==> ok
// "too long" ==> failed
// 12 ==> ok
// -1 ==> failed
oneOf
给定的数据必须对给定的一个子模式有效(XOR操作)。
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
// 10 ==> ok
// 2 ==> failed
// 7 ==> ok
// 15 ==> failed
4. Json schema 常用的在线工具
5. gojsonschema
package main
import (
"fmt"
"github.com/xeipuuv/gojsonschema"
)
func main() {
schemaLoader := gojsonschema.NewReferenceLoader("file://./schema.json") // 从文件加载
documentLoader := gojsonschema.NewStringLoader(`{"a":"b"}`) // 待校验的json数据
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
if err != nil {
panic(err.Error())
}
if result.Valid() {
fmt.Printf("The document is valid\n")
} else {
fmt.Printf("The document is not valid. see errors :\n")
for _, desc := range result.Errors() {
fmt.Printf("- %s\n", desc)
}
}
}
参考资料
《Getting Started Step-By-Step》
《JSON Schema Validation: A Vocabulary for Structural Validation of JSON》