【Ajv】JSON Schema Validator

Dear,大家好,我是“前端小鑫同学”,😇长期从事前端开发,安卓开发,热衷技术,在编程路上越走越远~


JSON Schema:

     JSON Schema是一份用来注释和验证JSON文档开源草案,通过JSON Schema可以描述现有的数据格式,可以完成数据的自动化测试,可以有效保障数据提交的质量。

Ajv介绍及使用:

     在JavaScript领域,Ajv 提供了完整的符合 JSON Schema 规范的数据校验。Ajv 的赞助商有moz://aMicrosoft等,使用Ajv的开源项目也非常多,如:ESLintwebpack等,并且在NodeJs浏览器桌面应用程序微信小程序等平台均有应用。

image.png

上手使用:

使用步骤说明:

  1. 安装、导入、实例化:
// npm i ajv
const Ajv = require('ajv');
const ajv = new Ajv();
  1. 定义schema;
  2. 执行compile生成validate函数;
  3. 执行validate函数检查数据。

schema定义说明:

  1. type设置为object表示目标JSON文档是一个对象;
  2. properties设置这个对象的属性包括foo、bar并分别指明其类型;
  3. required通过列表的形式限制foo为必填项;
  4. additionalProperties设置为false表示仅能包已声明的属性**。**

常见类型的定义:

  1. 定义对象类型:
const schema = {
type: 'object',
properties: {
attribute1,
attribute2,
...
},
required: ['attribute1'], // 必填属性
additionalProperties: false, // 禁止多余属性
}
  1. 定义字符串类型:
const schema = {
type: 'string',
minLength: 10, // 最小长度需满足10
}
  1. 定义数字类型:
const schema = { type: 'number' }
  1. 定义布尔类型:
const schema = { type: 'boolean' }
  1. 定义数组/类数组类型:
const schema = {
type: 'array',
items: {
type: 'string' // 定义数组的每一项均为字符串类型
}
}
// and
const schema = {
type: 'array',
items: [ // 定义数据包含两个元素,元素1位数字类型,元素2为字符串类型
{
type: 'number'
},{
type: 'string'
}
]
}

案例代码:

运行下面的代码会同时得到三条违反规则的提示:

  1. fn1:must NOT have additional properties,不需要额外的属性出现。
  2. /foo:must be integer,仅支持整数。
  3. /bar:must be string,仅支持字符串。
const Ajv = require('ajv');
const ajv = new Ajv({ allErrors: true });
const schema = {
type: 'object',
properties: {
foo: {
type: 'integer',
},
bar: {
type: 'string',
},
},
required: ['foo'],
additionalProperties: false,
};
// 执行compile后validate可以多次使用
const validate = ajv.compile(schema);
const data = {
foo: 'foo',
bar: 200,
fn1: 'fn1',
};
// 执行数据校验
const valid = validate(data);
if (!valid) {
console.log(validate.errors);
}

Format关键字:

使用步骤说明:

从ajv7开始由ajv-formats提供属性的format工作。

  1. 安装、导入、初始化:
// npm i ajv-formats
const addFormats = require('ajv-formats');
// ajv 实例化后添加
addFormats(ajv);
  1. 内置的format关键字有:date、time、date-time、uri、url、email等。
  2. format仅作用于类型为string或number的属性。

自定义Format:

  1. 使用addFormat增加一个通过正则验证完成的Format:
ajv.addFormat("identifier", /^a-z\$_[a-zA-Z$_0-9]*$/)
  1. 仅作用在number类型上的Format:
ajv.addFormat("byte", {
type: "number",
validate: (x) => x >= 0 && x <= 255 && x % 1 == 0,
})

案例代码:

const Ajv = require('ajv');
const addFormats = require('ajv-formats');
const ajv = new Ajv({ allErrors: true });
addFormats(ajv);
const schema = {
type: 'object',
properties: {
email: {
type: 'string',
format: 'email',
},
},
};
// 执行compile后validate可以多次使用
const validate = ajv.compile(schema);
const data = {
email: '1825203636@qq.com',
};
// 执行数据校验
const valid = validate(data);
if (!valid) {
console.log(validate.errors);
}

自定义关键字:

     自定义关键字可以弥补预定义字段无法完成的验证场景,简化程序结构。 实现range关键字:

const schema = {
type: "object",
properties: {
username: { type: "string" },
password: { type: "string" },
age: { type: "number" },
// 验证邮箱的长度在 5~25 个字符之间
email: { type: "string", format: "email", range: [5, 25] },
},
required: ["username", "password"],
additionalProperties: false,
};

用“validate”函数定义关键字:

     通过addKeyword函数新增一个使用validate定义的关键字校验,满足在执行ajv.validate时邮箱的字段长度符合一定的区间。

ajv.addKeyword({
keyword: "range",
validate: (schema, data) => {
if (typeof schema == "object" && schema !== null && data) {
const minLength = schema[0];
const maxLength = schema[1];
if (data.length >= minLength && data.length <= maxLength) {
return true;
}
}
return false;
},
errors: false,
});

用"compile"函数定义关键字:

ajv.compile阶段会对关键字的类型进行校验,保证关键字的正确使用。

ajv.addKeyword({
keyword: "range",
compile([minLength, maxLength], parentSchema) {
// parentSchema:读取 schema 中更多的信息来做判断
return (data) => {
if (data.length >= minLength && data.length <= maxLength) {
return true;
}
return false;
};
},
// 规范自定义关键字的类型
metaSchema: {
type: "array",
items: [{ type: "number" }, { type: "number" }],
minItems: 2,
maxItems: 2,
additionalItems: false,
},
errors: false,
});

用“宏”函数定义关键字:

     通过定义macro类型关键字可以很方便的通过一个关键字来为 schema 定义批量增加数据校验。

ajv.addKeyword({
keyword: "range",
macro: ([minLength, maxLength], parentSchema) => {
return { minLength, maxLength };
},
errors: false,
});

多语言支持:

使用步骤说明:

  1. 安装、导入、初始化:
// npm i ajv-i18n
const localize = require("ajv-i18n");
// 校验未通过后对错误内容进行转换处理
localize.zh(validate.errors);

案例代码:

const Ajv = require("ajv");
const addFormats = require("ajv-formats");
const localize = require("ajv-i18n");
const ajv = new Ajv();
addFormats(ajv);
ajv.addKeyword({
keyword: "range",
macro: ([minLength, maxLength], parentSchema) => {
return { minLength, maxLength };
},
errors: false,
});
const schema = {
type: "object",
properties: {
username: { type: "string" },
password: { type: "string" },
age: { type: "number" },
email: { type: "string", format: "email", range: [5, 15] },
},
required: ["username", "password"],
additionalProperties: false,
};
const data = {
username: "xiaoxin",
password: "xiaoxin",
email: "1825203636@qq.com",
};
const validate = ajv.compile(schema);
const valid = validate(data);
if (!valid) {
localize.zh(validate.errors);
console.log(validate.errors);
}

image.png

自定义错误信息:

使用步骤说明:

  1. 安装、导入、配置:
// npm i ajv-errors
// ajv实例化后执行
require("ajv-errors")(ajv);
// 配置字段的新属性errorMessage,针对类型和其他关键字做不同的错误提示:
errorMessage: {
type: "必须是字符串",
minLength: "输入的用户名太短了",
}
  1. i18 库存与ajv-errors似乎需要特殊处理;

案例代码:

const Ajv = require("ajv");
const ajv = new Ajv({ allErrors: true });
require("ajv-errors")(ajv);
ajv.addKeyword({
keyword: "range",
macro: ([minLength, maxLength], parentSchema) => {
return { minLength, maxLength };
},
errors: false,
});
const schema = {
type: "object",
properties: {
username: {
type: "string",
minLength: 10,
errorMessage: {
type: "必须是字符串",
minLength: "输入的用户名太短了",
},
},
password: { type: "string" },
age: { type: "number" },
email: { type: "string", range: [5, 25] },
},
required: ["username", "password"],
additionalProperties: false,
};
const data = {
username: "xiaoxin",
password: "xiaoxin",
email: "1825203636@qq.com",
};
const validate = ajv.compile(schema);
const valid = validate(data);
if (!valid) {
console.log(validate.errors);
}

image.png

posted @   前端小鑫同学  阅读(199)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示