我有一个对象,其中包含一个或多个类型为date的属性。我想使用 ajv json 架构验证器包来验证对象。我可以使用 toISOString(( 将日期类型的属性转换为字符串。但是对象可以安静地大,因此我不想转换整个对象的所有日期属性。除了将日期转换为字符串之外,还有其他解决方案吗?我可以以某种方式创建自定义 ajv 架构验证器吗?
// My example schema
const schema = {
"properties": {
"createdAt": {
"type": "string",
"format": "date-time"
},
"lastName": { "type": "string" },
"firstName": { "type": "string" }
}
};
// My example testobject
const testObj = {
createdAt: new Date(),
lastName: "Doe",
firstName: "John"
}
// The validation
const validate = ajv.compile(schema);
const valid = validate(testObj);
if(!valid) console.log('Invalid: ' + ajv.errorsText(validate.errors));
这将执行控制台日志,因为testObj.createdAt是一个日期而不是一个字符串。
只需将 ajv 架构从 "type": "string"
更改为 "type": "object"
,内置的 ajv 日期时间格式即可。 这是一个工作的小提琴。
您还可以定义自定义 ajv 格式来验证 Date 对象(或字符串(,如下所示:
ajv = new Ajv();
ajv.addFormat('custom-date-time', function(dateTimeString) {
if (typeof dateTimeString === 'object') {
dateTimeString = dateTimeString.toISOString();
}
return !isNaN(Date.parse(dateTimeString)); // any test that returns true/false
});
。并在 AJV 架构中调用自定义格式,如下所示:
const schema = {
"properties": {
"createdAt": {
"type": "object",
"format": "custom-date-time"
将它们放在一起,这是创建自定义日期格式的代码和工作小提琴:
// My example schema
const schema = {
"properties": {
"createdAt": {
"type": "object",
"format": "custom-date-time"
},
"lastName": {
"type": "string"
},
"firstName": {
"type": "string"
},
"required": [ 'createdAt', 'lastName', 'firstName' ],
"additionalProperties": false,
}
};
// My example testobject
const testObj = {
createdAt: new Date(),
lastName: "Doe",
firstName: "John"
}
// The validation
ajv = new Ajv();
ajv.addFormat('custom-date-time', function(dateTimeString) {
if (typeof dateTimeString === 'object') {
dateTimeString = dateTimeString.toISOString();
}
return !isNaN(Date.parse(dateTimeString)); // return true/false
});
const validate = ajv.compile(schema);
const valid = validate(testObj);
if (valid)
alert('valid');
else
alert('Invalid: ' + ajv.errorsText(validate.errors));
其中一个有效的方法是首先转换为与 JSON 架构兼容的对象。
function makeJsonSchemaCompatible (obj) {
if (Array.isArray(obj)) {
return obj.map((subObj) => makeJsonSchemaCompatible(subObj))
} else if (obj && typeof obj === 'object') {
const replacement = {}
const className = obj.constructor.name
if (className !== 'Object') {
replacement.__className = className
}
Object.entries(obj).map(([k, v]) => { replacement[k] = makeJsonSchemaCompatible(v) })
return replacement
}
return obj
}
不幸的是,format
属性不适用于object
类型,因此自定义格式不是一个选项。但是,我能够添加一个自定义关键字(灵感来自查看instance
关键字,它实际上可以让您完成一半(,这给了我所需的结果(即值必须是 Date 对象并且 Date 必须有效(。
const { equal } = require('assert');
const Ajv = require('ajv');
const { _ } = require('ajv');
const ajv = new Ajv();
const schema = {
type: 'object',
properties: {
jsdate: {
type: 'object',
isDate: true,
},
},
};
ajv.addKeyword({
keyword: 'isDate',
type: 'object',
code(ctx) {
const { data } = ctx;
ctx.pass(_`${data} instanceof Date && !isNaN(+${data})`);
},
});
const validate = ajv.compile(schema);
equal(validate({ jsdate: new Date() }), true, 'should succeed');
equal(validate({ jsdate: {} }), false, 'should fail for random object');
equal(
validate({ jsdate: '2001-01-01' }),
false,
'should fail for valid date string'
);
equal(
validate({ jsdate: new Date('rubbish') }),
false,
'should fail if Date is invalid'
);
似乎您可以使用 instanceof
关键字(ajv 关键字的一部分(来达到预期的结果:.
const Ajv = require("ajv");
const addKeywords = require("ajv-keywords");
const ajv = new Ajv(); // options can be passed, e.g. {allErrors: true}
addKeywords(ajv);
// My example schema
const schema = {
type: "object",
properties: {
createdAt: {
instanceof: "Date",
},
lastName: { type: "string" },
firstName: { type: "string" },
},
};
// My example testobject
const testObj = {
createdAt: new Date(),
lastName: "Doe",
firstName: "John",
};
// The validation
const validate = ajv.compile(schema);
const valid = validate(testObj);
if (!valid) console.log("Invalid: " + ajv.errorsText(validate.errors));