ajv
- ajv-validator/ajv
- JSON Schema 校验
 - 支持 JTD serialize/parse
 
 - 参考
- ajv-validator/ajv-keywords
增加自定义关键字
- typeof, instanceof
 select, selectCases, selectDefault-> discriminator- dynamicDefaults
 - number: range, exclusiveRange
 - string: regexp, transform
- transform 允许验证时修改字符串内容
 
 - array: uniqueItemProperties
 - object: allRequired, anyRequired, oneRequired, patternRequired, prohibited, deepProperties, deepRequired
 
 - https://ajv.js.org/json-schema.html
 - https://validatejs.org/
 
 - ajv-validator/ajv-keywords
增加自定义关键字
 
caution
- 不能扩展 type
 - additionalProperties 不能默认为 false
 
npm add ajv ajv-formats ajv-keywords ajv-errors
import addFormats from 'ajv-formats';
import addKeywords from 'ajv-keywords';
import Ajv2020 from 'ajv/dist/2020';
const ajv = new Ajv2020();
addFormats(ajv);
addKeywords(ajv);
// 添加自定义 keyword 避免失败
ajv.addKeyword('x-meta');
| format | example | description | 
|---|---|---|
| ajv-formats | ||
| date | 2021-01-01 | RFC3339 full-date | 
| time | 14:30:00+01:00 | time with optional time-zone. | 
| date-time | 2021-01-01T14:30:00+01:00 | date-time from the same source (time-zone is mandatory). | 
| duration | P3Y6M4DT12H30M5S | RFC3339 duration | 
| uri | https://example.com | full URI. | 
| uri-reference | /relative/uri | URI reference, including full and relative URIs. | 
| uri-template | https://example.com/{user} | RFC6570 URI template | 
| https://example.com | URL record | |
| [email protected] | email address. | |
| hostname | example.com | RFC1034 host name | 
| ipv4 | 192.168.0.1 | IPv4 | 
| ipv6 | 2001:0db8:85a3:0000:0000:8a2e:0370:7334 | IPv6 | 
| regex | ^[a-zA-Z0-9]+$ | RegExp | 
| uuid | 123e4567-e89b-12d3-a456-426614174000 | RFC4122 UUID | 
| json-pointer | /pointer | RFC6901 JSON-pointer | 
| relative-json-pointer | 0 | draft relative JSON-pointer | 
| ajv-formats-draft2019 | ||
| iri | https://例子.测试 | RFC3987 IRN/Internationalized Resource Identifier | 
| iri-reference | /relative/路径 | IRI reference, including full and relative IRIs. | 
| idn-hostname | 例子.测试 | RFC5890 IDN/Internationalized Domain Name hostname | 
| idn-email | 用户@例子.测试 | RFC6531 Internationalized email address | 
// 自定义 format
ajv.addFormat('identifier', /^a-z\$_[a-zA-Z$_0-9]*$/);
// 使用自定义逻辑校验 format
ajv.addFormat('byte', {
  type: 'number',
  validate: (x) => x >= 0 && x <= 255 && x % 1 == 0,
});
ajv.addFormat('int8', {
  type: 'number',
  validate: (x) => x >= -128 && x <= 127 && Number.isInteger(x),
});
standalone validation code
- 生成独立的函数
 
npm install -g ajv-cli
ajv compile -s schema.json -o validate_schema.js
addKeyword
FAQ
due to error strict mode: unknown keyword
ajv schema with key or id already exists
- 如果 schema 有 
$id可能会出现 - 如果 schema 是通过反序列化生成的,可能会出现重复 - ref 不一样但 id 一样
 
strict mode: unknown keyword
未知关键字,需要添加关键字支持
修改校验数据
类似 zod.parse 能得到一个解析后的满足验证要求的对象,不过 zod 不会修改传入对象,ajv 只能通过修改传入对象实现,这一点上 ajv 性能更好
- 移除额外
 - 添加 defaults
 - 强制类型转换
 - coerceTypes=true|'array'
- array 支持 
x<->[x] 
 - array 支持 
 
const ajv = new Ajv({ removeAdditional: true, useDefaults: true, coerceTypes: 'array' });
const schema = {
  type: 'object',
  additionalProperties: false,
  properties: {
    foo: { type: 'array', items: { type: 'number' } },
    bar: { type: 'boolean' },
    num: { type: 'number' },
    name: { type: 'string', default: 'wener' },
  },
};
const data = { foo: '1', bar: 'false', rm: true, num: '10' };
const validate = ajv.compile(schema);
// true
console.log(validate(data));
// {foo: [1], bar: false, num: 10, name: "wener"}
console.log(data);