前言
在学习Mall-Cook低代码平台时第一次接触JsonSchema,get到利用JsonSchema可快速生成一个属性面板表单组件,对于开发一个业务组件简直是个利器。
但对于JsonSchema的认知仅停留局限在有清晰的数据结构描述,数据格式的团队弱约束上,但其实JsonSchema的作用,可远不是弱约束(只是团队内部人员达成共识哪些字段需要,字段起名规则,字段值的约定),它可以通过一系列的关键字实现 强大的验证和强约束;同时也有丰富的数据类型支持;还有强大的拓展能力,跨语言能力;利用这些特性,我们可以实现像通过表单的rules一样对于我们的json数据有更加精细且强制的校验。
本文将通过以下几点来进一步沉淀对于JsonSchema的理解,结合实际的demo实践进一步验证JsonSchema的强大能力。
JsonSchema是什么?
描述json数据结构的声明式格式,本身就是一个json文件。
有什么特性
优:
可简明的描述数据格式和结构,并能根据配置的关键字和对应的值,自行校验数据。这点很有效。
跨开发编程语言,他只是一种数据格式,可在各种环境中使用。
构建复杂模式 可达到 模式抽离,嵌套,复用效果,便于维护,逻辑结构更清晰。
限制:
但jsonSchema本身就是一个json文件,数据之间的关联及逻辑关系这种语义化描述上有所限制,需要结合具体的开发编程语言来实现。
关键概念理解
声明方言:
json schema的版本被称为方言。使用$schema关键字来约定,每个json schema文件都必须要有此配置,且位于根级别,嵌套模式下,也需要有自己的$schema配置,版本可以不一致。
模式:
每一个json schema文件就是一个模式,模式中引用其他模式的情况被称为 复杂模式。没有标识符的模式被称为 匿名模式
关键字:
这个就不用说啦,json schema就是通过一系列关键字来实现对于数据结构的描述。(如:type类型关键字,$schema方言关键字,properties属性对象关键字等)
标识符:
一个模式引用其他模式时需要有一个标识符(其实就是路径引用)。
有哪些标识符?
URI/非相对URI: 全量地址,https://***.com/a/c#demo
相对-URI引用:不包含http://**.com域名部分之后的内容,如 /a/c#demo,#/demo,
URI-引用:全量地址,或者是相对-URI
绝对URI: 不包含锚点后的地址,https://***.com/a/c,https://***.com
哪些关键字可以设置标识符?
$id: 推荐设置绝对URI,作为模式的基础URI,模式的唯一标识符。对于此模式下引用
其他模式时,作为拼接引用基础路径很有用.(如:https://***.com#/a/c)
$ref: 1.设置相对-URI,用来引用其他模式。(如:/d/e),常见于$defs中的捆绑模式;
2.设置带#的相对-URI
json指针。(如:https://***.com/a/c#/d/e),此种解析相当于引用 https://***.com/a/c 这个模式下 键d的值中键e的值(类似对象中键值访问)
锚点。(如:https://***.com/a/c#d)需要配合$anchor使用,引用外部模式;
(#d),需要配合$anchor使用,引用内部模式;
引用仅内部使用的模式。(如#/$defs/a)
模式识别:
一个模式a 引用其他模式b时 需要有一个标识符,当模式b被标识符引用时,就是模式b被识别的过程。
$defs关键字:
一个模式只仅限于某个模式内部使用,可用$defs标记抽离为子模式,子模式的写法和一般模式写法一样。(简单可以理解为仅提供给函数内部使用 无需单独抽离 的对象。)
JSON指针
JSON 指针描述了一个以斜线分隔的路径来遍历文档中对象中的键。参考上述的$ref中第2条。
规范
json schema的规范标准修订过多次,目前最新版本是7,版本4被广泛使用。以下的demo以最新的版本为例,不同版本对不同标准的支持程度及差异,请参考官网差异
$schema:
规定此文件为json-schema文件,且声明写入的json模式规范是哪个版本;
$id:
模式唯一标识符
类型关键字type:
限定接收的数据特定类型;
常用通用关键字:
title:此模式的title
description: 此模式的具体描述
default: 一个默认值,不用于空值的占位填充,只是用来提示如何填写/使用此值。
enum: 限定一组固定值的数据,每个元素唯一。固定枚举值很有用。
const: 限定值是一个特定值
readOnly:只读,通常用于接口api上下文
writeOnly:只改,通常用于接口api put类型上下文
$comment: 注释
用于组合模式关键字:
在其他关键字的基础上叠加以下关键字,可实现 体现并约束一些复杂的模式 功能。无需 构建复杂模式那样 需要多个模式叠加实现。
allOf: 值为数组,每个数组项都是一个模式,给定的数据 必须通过每个模式的校验
anyOf: 值为数组,每个数组项都是一个模式,给定的数据 需要通过任意1个或者多个模式的验证
oneOf: 值为数组,每个数组项都是一个模式,给定的数据 必须且只能通过其中1个模式的验证
not: 值为对象,给定数据不能满足此模式,才算验证通过
必要依赖关键字:
dependentRequired:{存在的key:['必须存在的key1','必须存在的key2']}
上述依赖项不是双向的,如果想要双向的,需要同样上述格式反过来再写一遍。
模式依赖关键字:
dependenciesSchemas:{
存在的key:{
properties:{
'必须存在的key1':{
type:'类型'
}
}
}
}
和dependentRequired的作用是一样的,只不过这里依赖的是一个模式
条件语句关键字:
以下 关键字允许基于一种模式来应用子模式(基于某些条件true/false来实现语义化的判断逻辑)
if/then/else:
if为true时,then必须也为true,整个schema才能为true。
if为false时不关心then,以else返回的true/false作为整个schema的校验结果。
构建复杂模式:
json schema可以像组件/方法一样,可以将公共的验证模式提取出来,不同模式相互引用,从而达到复用,组合成更符合业务场景的复杂模式。一般是通过 $id,$ref,$defs,$anchor这几个关键字来组合实现。
如何代码中体现这些特性
工欲善其事必先利其器,先推荐几个工具,大家可快速的在线验证自己的schema内容是否书写正确,同时可快速验证值是否符合schema的要求;
JSON Schema Validator 在线验证工具 (如果要验证$ref模式相关引用的场景,推荐使用此工具,上面那个工具不支持此场景)
以上所有的规范具体的代码实践请参考
jsonSchema 规范代码仓https://github.com/zhangpanjun/jsonSchema
(每个demo都包含2个文件,一个是盛放schema的json文件,一个是盛放数据的js文件,可将schema和js的值分别贴到 ‘在线json schema验证工具’ 的左右两边,即可实时验证。)
能做些什么(适用场景)
根据json数据格式快速生成动态form表单;
输入数据的快速验证,ajv是json schema践行者之一的插件,ajv插件被广泛应用在代码的规范插件中,例如:eslint 。
另外,使用npm下载下来的很多插件中都有ajv对于插件内部数据格式的验证的身影。(比如webpack)
拓展插件
关于json schema的践行者有很多第三方插件,这些插件既可以支持不同json结构草案,还可以支持自定义一些内容,同时提供更加方便的api来快速验证。
这里推荐ajv插件,具体的实践demo请移步代码仓 GitHub - zhangpanjun/ajv-demos: Ajv 可以将 JSON 结构转换为超快速的校验函数,实现对json schema规则下的json输入数据快;本项目是基于ajv插件实现的一些基础用法demos