[top]
介绍
Json Schema定义了一套词汇和规则,这套词汇和规则用来定义Json元数据,且元数据也是通过Json数据形式表达的。Json元数据定义了Json数据需要满足的规范,规范包括成员、结构、类型、约束等
eg:
{
"city":"chicago",
"number": 20,
"user" : {
"name":"Alex",
"age":20
}
}
在上面的例子中,web api要求提供city,number,user三个成员,其中city是字符串,number是数值,user是一个对象,又包含了name和age两个成员
对应的Json Schema如下:
{
"type": "object",
"properties": {
"city": { "type": "string" },
"number": { "type": "number" },
"user": {
"type": "object",
"properties": {
"name" : {"type": "string"},
"age" : {"type": "number"}
}
}
}
}
关键字
type 类型
1.String
1.字符串长度 **关键字: minLength, maxLength** 对字符串的最小长度、最大长度做规范
eg:
{ "type" : "string", "minLength" : 2, "maxLength" : 3, }
- 正则表达式
**关键字: pattern**
eg:
{ "type" : "string", "pattern" : "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$", }
- 字符串Format
**关键字: format**用于电子邮件、日期、域名等
{ "type" : "string", "format" : "date", }
2.Object
- Json对象是最常见的Json数据类型,合法的数据可以是
{
"name": "Froid",
"age" : 26,
"address" : { "city" : "New York", "country" : "USA" }
}
- 成员的Schema
**关键字:properties**
{
"type": "object",
"properties": {
"name": {"type" : "string"},
"age" : {"type" : "integer"
},
"address" : {
"type" : "object",
"properties" : {
"city" : {"type" : "string"},
"country" : {"type" : "string"}
}
}
}
}
对于上例中的Schema,合法的data是
{
"name": "Froid",
"age" : 26,
"address" : {
"city" : "New York",
"country" : "USA"
}
}
- 批量定义成员Schema
**关键字:patternProperties**
eg: {"S_1" : "abc"}
{"S_1" : "abc", "I_3" : 1}
{
"type": "object",
"patternProperties": {
"^S_": { "type": "string" },
"^I_": { "type": "integer" }
}
}
- 必须出现的成员
**关键字:required**
{
"type": "object",
"properties": {
"name": {"type" : "string"},
"age" : {"type" : "integer"},
},
"required" : ["name"]
}
上例中"name"成员是必须的,因此合法的数据可以是
{"name" : "mary", "age" : 26}
{"name" : "mary"}
但缺少"name"则是非法的
{"age" : 26}
- 成员依赖关系
**关键字:dependencies**
规定某些成员的依赖成员,不能在依赖成员缺席的情况下单独出现,属于数据完整性方面的约束。
{
"type": "object",
"dependencies": {
"credit_card": ["billing_address"]
}
}
dependencies也是一个字典结构,key是Json数据的属性名,value是一个数组,数组内也是Json数据的属性名,表示key必须依赖的其他属性
上面Json Schema合法的数据可以是
{}
{"billing_address" : "abc"}
但如果有"credit_card"属性,则"billing_address" 属性不能缺席。下面的数据是非法的
{"credit_card": "7389301761239089"}
- 是否允许额外属性
**关键字:additionaProperties**
规定object类型是否允许出现不在properties中规定的属性,只能取true/false
{
"type": "object",
"properties": {
"name": {"type" : "string"},
"age" : {"type" : "integer"},
},
"required" : ["name"],
"additionalProperties" : false
}
上例中规定对象不能有"name"和"age"之外的成员。
合法的数据
{"name" : "mary"}
{"name" : "mary", "age" : 26}
非法的数据
{"name" : "mary", "phone" : ""84893948}
- 属性个数的限制
**关键字:minProperties, maxProperties**规定最少、最多有几个属性成员
{
"type": "object",
"minProperties": 2,
"maxProperties": 3
}
合法数据
{"name" : "mary", "age" : 26}
{"name" : "mary", "age" : 26, "phone" : "37839233"}
3.Number
1.number的合法数值可以是 2或0.1 而 integer只能是整数
2.**关键字:multipleOf**
要求数值必须是10的整数倍
{ "type" : "number", "multipleOf" : 10, }
3.**关键字: minimum, maximum, exclusiveMinimum, exclusiveMaximum**可以限制数值的方位,包括最大值、最小值、开区间最大值、开区间最小值
要求数值在[0, 100)范围内:
{
"type" : "number",
"minimum": 0,
"exclusiveMaximum": 100
}
4.Integer 要求数据必须是整数
5.Array
1.Json数组合法数据
[1, 2, 3]
[1, "abc", {"name" : "alex"}]
[]
2.数组的类型特定参数,可以用来限制成员类型、是否允许额外成员、最小元素个数、最大元素个数、是否允许元素重复
- 数组成员类型
**关键字: items**
1.可以要求数组内每个成员都是某种类型,通过关键字items实现
{
"type": "array",
"items": {
"type":
"number"
}
}
2.关键字items还可以对应一个数组,这时Json数组内的元素必须与Json Schema内items数组内的每个Schema按位置一一匹配
eg: [1, "abc"]
{
"type": "array",
"items": [
{"type": "number" },
{ "type": "string" }
]
}
- 数组是否允许额外成员
**关键字: additionalItems**
当使用了items关键字,并且items关键字对应的是Schema数组,这个限制才起作用。
关键字additionalItems规定Json数组内的元素,除了一一匹配items数组内的Schema外,
是否还允许多余的元组。当additionalItems为true时,允许额外元素
eg:[1, "abc", "x"]
{
"type": "array",
"items": [
{ "type": "number" },
{ "type": "string" }
],
"additionalItems" : true
}
- 数组元素个数
**关键字: minItems, maxItems**可以限制数组内元素的个数
eg:[1,2,3,4,5,6]
{
"type": "array",
"items": { "type": "number" },
"minItems" : 5,
"maxItems" : 10
}
- 数组内元素是否必须唯一
**关键字: uniqueItems**
eg:[1,2,3,4,5]
{
"type": "array",
"items": { "type": "number" },
"uniqueItems" : true
}
6.Boolean
{"type" : "boolean"}
7.null
{"type" : "null"}
8.逻辑组合**关键字:allOf, anyOf, oneOf, not**
- 从关键字名字可以看出其含义,满足所有、满足任意、满足一个。前三个关键字的使用形式是一致的,以allOf为例说明其形式
{
"allOf" : [
Schema1,
Schema2, ...
]
}
其中,"allOf"的内容是一个数组,数组内的成员都是内嵌的Json Schema。上例Schema1、Schema2都是内嵌的Json Schema。整个Schema表示当前Json数据,需要同时满足Schema1、Schema2。
需要注意,不论在内嵌的Schema里还是外部的Schema里,都不应该使"additionalProperties"为false。否则可能会生成任何数据都无法满足的矛盾Schema。
可以用来实现类似“继承”的关系,例如我们定义了一个Schema_base,如果想要对其进行进一步修饰,可以这样来实现。
{
"allOf" : [ Schema_base ],
"properties" : {
"other_pro1" : {"type" : "string"},
"other_pro2" : {"type" : "string"}
},
"required" : ["other_pro1", "other_pro2"]
}
Json数据既需要满足Schema_base,又要具备属性"other_pro1"、"other_pro2"。
- 关键字
not规定 Json不能满足not所对应的Schema
只要不是string类型的都Json数据都可以
{ "not" : {"type" : "string"} }
9.复杂结构
**关键字:无**
定义一个类型,并不需要特殊的关键字。通常的习惯是在root节点的definations下面,定义需要多次引用的schema。definations是一个json对象,key是想要定义的“类型”的名称,value是一个json 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" }
}
}
上例中定义了一个address的schema,并且在两个地方引用了它,`#/definitions/address`表示从根节点开始的路径
**关键字:$id**
可以在上面的定义中加入id属性,这样可以通过id属性,这样可以通过id属性的值对该schema进行引用,而不需要完整的路径。
"address": {
"type": "object",
"$id" : "address",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
**关键字:$ref**
关键字`$ref`可以用在任何需要使用json schema的地方。如上例中,billing_address的value应该是一个json schema,通过一个`$ref`替代了。
`$ref`的value,是该schema的定义在json中的路径,以#开头代表根节点。
{
"properties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": { "$ref": "#/definitions/address" }
}
}
如果schema定义了$id属性,也可以通过该属性的值进行引用。
{
"properties": {
"billing_address": { "$ref": "#address" },
"shipping_address": { "$ref": "#address" }
}
}
10. 通用关键字
- enum
**关键字:enum**
可以在任何json schema中出现,其value是一个list,表示json数据的取值只能是list中的某个
{
"type": "string",
"enum": ["red", "amber", "green"]
}
上例的schema规定数据只能是一个string,且只能是"red"、"amber"、"green"之一。
- metadata
**关键字:title,description,default,example**
{
"title" : "Match anything",
"description" : "This is a schema that matches anything.",
"default" : "Default value",
"examples" : [
"Anything",
4035
]
}
只作为描述作用,不影响对数据的校验
基础学习
AJV网站
校验数据 AJV
JSON Schema keywords
1.校验数据
const schema = {
type:'string',
minLength:10
}
const data = 'ww'
const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) console.log(validate.errors)
[
{
keyword: 'minLength',//判断错误的字段 说明长度不够10
dataPath: '',
schemaPath: '#/minLength',
params: { limit: 10 },
message: 'should NOT be shorter than 10 characters'
}
]
2.关键字 Formats (只针对string和number类型,其他不起作用)
1.在AJV网站中搜索Formats 相关介绍
3.自定义format
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type:'object',
properties:{
name:{
type:'string',
format:'test'//格式为自定义的test
},
}
//addFormat是ajv提供的 并非是Json Schema提供
ajv.addFormat('test',(data)=>{
console.log(data,'-----')
return data === 'haha' //格式必须为haha
})
const data = {
name:'haha'
}
const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) console.log(validate.errors)
4.自定义关键字
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type:'object',
properties:{
name:{
type:'string',
test:false
// minLength:10
},
age:{
type:'number'
},
pets:{
type:'array',
items:{
type:'string'
}
},
isWorker:{
type:'boolean'
}
},
required:['name','age']
}
//第一种 addKeyword方式
// ajv.addKeyword('test',{
// validate(schema,data){
// console.log(schema,data);//true haha
// if(schema){
// return true
// }else {
// return schema.length === 6
// }
// }
// })
//第二种 compile
// ajv.addKeyword('test',{
// compile(sch,parentSchema){
// console.log(sch,parentSchema);//false { type: 'string', test: false }
// return ()=> true//要return一个函数
// },
// metaSchema:{//校验test值必须为boolean
// type:'boolean'
// }
// })
//第三种 推荐用
ajv.addKeyword('test',{
macro(){
return {
minLength:10//长度为10
}
}
})
const data = {
name:'haha',
age:10,
pets:["mimi","mama"],
isWorker:true
}
const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) console.log(validate.errors)
5.如何改变错误信息的提示语言 ajv-i18n
(1)安装 yarn add ajv-i18n -S或 npm install ajv-i18n
(2)在AJV官网搜索Usage 选择含有ajv-i18n 有相关用法
const Ajv = require("ajv") // version >= 8.0.0
const localize = require("ajv-i18n") //引入
// or for JSON Type Definition
// const localize = require("ajv-i18n/localize/jtd")
const ajv = Ajv({allErrors: true, messages: false})
const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) {
// ru for Russian
//localize.ru(validate.errors)//第一种调用
localize.zh(validate.errors)//第二种调用
// string with all errors and data paths
console.log(ajv.errorsText(validate.errors, {separator: '\n'}))
}
6.定义json schema关键字校验不通过 的错误信息定制 ajv-errors
npm install ajv-errors
const Ajv = require('ajv')
const ajv = new Ajv({allErrors: true,jsonPointers:true})//注意这里的写法
require("ajv-errors")(ajv /*, {singleError: true} */)
const schema = {
type:'object',
properties:{
name:{
type:'string',
//test:false,
minLength:10,
errorMessage:{//针对不同错误作不同提示
type:'必须是字符串',
minLength:'长度不能小于10'
}
}
}
}
//第三种 推荐用
ajv.addKeyword('test',{
macro(){
return {
minLength:10
}
}
})
const data = {
name:11
}
const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) {
console.log(validate.errors)
}