如何为AJV Schema添加自定义验证函数(无需新增关键字)
无需新增Schema关键字,给AJV添加自定义日期范围校验
要实现date_fr始终小于date_to的校验需求,且不修改原有Schema、不添加额外关键字,可通过包装AJV标准验证函数的方式实现,具体步骤如下:
1. 初始化AJV实例
创建AJV实例并开启全错误返回,便于调试所有校验问题:
const Ajv = require('ajv'); const ajv = new Ajv({ allErrors: true });
2. 编写日期范围校验逻辑
实现单条日期记录的校验函数,处理date_to可选的业务场景:
function checkDateRange(dateItem) { // date_to为可选字段,不存在时直接通过校验 if (!dateItem.date_to) return true; // 若date_fr为空,直接判定不合法(业务允许可选时可调整此逻辑) if (!dateItem.date_fr) return false; const dateFrom = new Date(dateItem.date_fr); const dateTo = new Date(dateItem.date_to); // 二次校验日期合法性(避免格式合法但实际无效的日期值) if (isNaN(dateFrom.getTime()) || isNaN(dateTo.getTime())) { return false; } // 核心校验规则:date_fr必须早于date_to return dateFrom < dateTo; }
3. 整合标准校验与自定义校验
先编译原有Schema得到标准验证函数,再包装一层,在标准校验通过后执行自定义日期校验,并将自定义错误信息整合到AJV的错误集合中:
// 编译原有Schema,生成标准验证函数 const validateStandard = ajv.compile(mySchema); // 包装验证函数,整合自定义校验逻辑 function validate(data) { // 先执行标准Schema校验,不通过直接返回结果 const isStandardValid = validateStandard(data); if (!isStandardValid) return false; // 遍历所有数据节点,执行自定义日期范围校验 data.forEach((listItem, listIndex) => { if (listItem.my_list_itm) { listItem.my_list_itm.forEach((dateItem, dateIndex) => { if (!checkDateRange(dateItem)) { // 将自定义错误添加到AJV错误列表,保持错误格式一致 validateStandard.errors.push({ instancePath: `/${listIndex}/my_list_itm/${dateIndex}`, keyword: 'customDateRange', message: 'date_fr必须早于date_to', params: { keyword: 'customDateRange' } }); } }); } }); // 若存在自定义错误,返回false;否则返回true return validateStandard.errors.length === 0; }
使用示例
调用包装后的validate函数即可完成完整校验:
const testData = [ { my_list_key: 'test1', my_list_itm: [ { date_fr: '2024-01-01', date_to: '2024-01-02' }, // 合法 { date_fr: '2024-02-01', date_to: '2024-01-01' } // 不合法 ] } ]; const isValid = validate(testData); if (!isValid) { console.error('校验失败:', validateStandard.errors); }
这种方案完全保留原有Schema结构,未添加任何额外关键字,同时将自定义校验与AJV标准校验深度整合,错误信息格式统一,便于前端或服务端处理。
内容的提问来源于stack exchange,提问作者targhs
相关产品推荐
相关产品推荐

