文章目录
概念
json-schema我觉得把它类比成json的增强interface就比较好理解。
引用:Json Schema定义了一套词汇和规则,这套词汇和规则用来定义Json元数据,且元数据也是通过Json数据形式表达的。Json元数据定义了Json数据需要满足的规范,规范包括成员、结构、类型、约束等。
安装
此次我们使用一个比较流行的基于json-schema标准实现的库,AJV。还是在vue3的项目上:
cnpm i ajv -S
使用
可以新建个src同级文件夹,里面放json-schema的测试文件,比如json-schema/test.js:
// 官方案例
const Ajv = require("ajv");
const ajv = new Ajv(); // options can be passed, e.g. {allErrors: true}
const schema = {
type: "object", // 类型
properties: {
// 对象上的属性(特征)
foo: { type: "number" },
bar: { type: "string" },
},
required: ["foo"], // 必输入项
additionalProperties: false,
};
const validate = ajv.compile(schema);
const data = {
foo: 1,
bar: 1, // 故意输错
};
const valid = validate(data);
if (!valid) console.log(validate.errors);
cd到文件夹下直接node test.js跑起来,会打印出:
{
instancePath: '/bar',
schemaPath: '#/properties/bar/type',
keyword: 'type', // 类型错误
params: { type: 'string' },
message: 'must be string' // 错误信息
}
可能在写的过程中,eslint会报错,需要在src同级下创建个.eslintignore文件用来忽略schema-tests文件下的检测:
schema-tests
format
感觉就是ajv内置的一些字符串和数字的校验规则。
其中的addFormat可以自定义format规则。
自定义关键字
类似type、properties等就是关键字。如何自定义关键字的内部逻辑有多种方案。
validate方案:
const Ajv = require("ajv");
const ajv = new Ajv();
const schema = {
type: "object",
properties: {
input: { type: "string", fnCheck: true },
},
};
ajv.addKeyword("fnCheck", {
validate(schema, data) { // addKeyword内部逻辑的现实有多种,先看看validate方案
// schema为新增fnCheck关键字的值,为true,data为添加这个关键字的对象的值,input为'1234'
if (data === "123") return true;
else return false;
},
});
const validate = ajv.compile(schema);
const data = {
input: "1234",
};
const valid = validate(data);
if (!valid) console.log(validate.errors);
此时运行就会提示没通过fnCheck的校验:
{
instancePath: '/input',
schemaPath: '#/properties/input/fnCheck',
keyword: 'fnCheck',
params: {},
message: 'must pass "fnCheck" keyword validation'
}
compile方案:
const Ajv = require("ajv");
const ajv = new Ajv();
const schema = {
type: "object",
properties: {
input: { type: "string", fnCheck: true },
},
};
ajv.addKeyword("fnCheck", {
compile(sch, parentSchema) {
// sch 为新增key的值,例如fnCheck的true。parentSchema取的是新增key所在的父级内容,也就是{ type: "string", fnCheck: true }
return () => true; // 注意的是要返回一个函数,如果你想返回值需要通过返回的函数再返回出去
},
metaSchema: {
type: "boolean", // 定义新增key值的类型
},
});
const validate = ajv.compile(schema);
const data = {
input: "1234",
};
const valid = validate(data);
if (!valid) console.log(validate.errors);
macro方案:
const Ajv = require("ajv");
const ajv = new Ajv();
const schema = {
type: "object",
properties: {
input: { type: "string", fnCheck: true, minLength: 10, maxLength: 20 },
},
};
ajv.addKeyword("fnCheck", {
macro() {
// 会把返回的内容全部加到新增key的下面
return {
minLength: 10,
maxLength: 20,
};
},
});
const validate = ajv.compile(schema);
const data = {
input: "1234",
};
const valid = validate(data);
if (!valid) console.log(validate.errors);
剩下一个inline方案,虽然性能上是最优的,但是可读性很差,就不记录了。