NodeJS 我可以使用ajv json模式验证日期,而不把日期转换成字符串吗?

sr4lhrrt  于 2023-01-25  发布在  Node.js
关注(0)|答案(4)|浏览(163)

我有一个包含一个或多个date类型属性的对象。我想使用ajv json模式验证器包验证该对象。我可以使用toISOString将date类型的属性转换为字符串().但是对象可能很大,因此我不想转换整个对象的所有日期属性。除了将日期转换为字符串之外,还有其他解决方案吗?我可以创建一个自定义的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是一个日期而不是字符串。

e4eetjau

e4eetjau1#

只需将ajv模式从"type": "string"更改为"type": "object",内置的ajvdate-time格式就可以工作了。
您还可以定义一个自定义的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"

下面是代码和一个working fiddle for creating a custom date format

// 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));
50few1ms

50few1ms2#

有效的方法之一是先转换为JSON Schema兼容的对象。

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
}
0s7z1bwu

0s7z1bwu3#

不幸的是,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'
);
a64a0gku

a64a0gku4#

看起来您可以通过使用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));

相关问题