我有一个类,允许我使用 AJV 根据模式验证 API 响应。它包括存储可重用模式块的
_definitionsHelper
对象:
import Ajv from 'ajv';
export default class SchemaUtilities {
validateSchema = (schema, response) => {
const ajv = new Ajv();
const validate = ajv.addSchema(this._definitionsHelper).compile(schema);
const valid = validate(response);
if (!valid) {
this._getSchemaError(validate.errors).then((schemaError) => {
throw new Error(`Schema validation failed. ${schemaError}`);
});
} else {
cy.log('Schema validated.');
}
};
private _definitionsHelper = {
$id: 'customDefinitions',
definitions: {
baseResponseProperties: {
type: 'object',
properties: {
errorCode: {
type: 'number'
},
responseCode: {
type: 'number'
},
},
required: ['errorCode', 'responseCode']
},
FOO: {
type: 'object',
properties: {
id: { type: 'number' },
definition: { type: 'number' },
url: { type: 'string' }
},
required: ['id', 'definition', 'url']
},
BAR: {
type: 'object',
properties: {
featureId: { type: 'number' },
order: { type: 'number' },
featureImageUrl: { type: 'string' },
navigationLinkType: { type: 'string' },
navigationLink: { type: ['string', 'null'] },
FOO: { type: ['object', 'null'], items: { $ref: 'customDefinitions#/definitions/FOO' } },
sku: { type: ['string', 'null'] },
yyyUrl: { type: ['string', 'null'] },
featureYYYAlignment: { type: ['string', 'null'] }
},
required: ['featureId', 'order', 'featureImageUrl', 'navigationLinkType', 'navigationLink', 'FOO', 'sku', 'yyyUrl', 'featureYYYAlignment']
}
},
};
private _getSchemaError = (getAjvError) => {
return cy.wrap(`Field: ${getAjvError[0]['instancePath']} is invalid. Cause: ${getAjvError[0]['message'].replace(',', ', found ')}`);
};
}
在 BAR 中,我将 FOO 的类型设置为
['object', 'null']
并从我的模拟 JSON 响应中删除了其中一个属性。
模拟 JSON 响应(已从 FOO 中删除了所需的“url”属性):
{
"errorCode": 0,
"responseCode": 0,
"BAR": [{
"featureId": 2,
"order": 2,
"featureImageUrl": "x",
"navigationLinkType": "x",
"navigationLink": null,
"FOO": {
"id": 2,
"definition": 2
},
"sku": "x",
"yyyUrl": null,
"featureYYYAlignment": "x"
}]
}
预期结果:应该抛出一个错误,表明需要删除的属性。
实际结果:验证成功。
故障排除:
从模拟 JSON 响应的根中删除了属性,以确保 AJV 在缺少所需属性时正确出错。是的。
在
_definitionsHelper
中,如果我将 FOO 的类型更改为 'array'
或 ['array', 'null']
并且在模拟 JSON 响应中,我将 FOO 的对象包装在数组中,AJV 会抛出预期的错误。但这对我来说没有用,因为 API 将 FOO 作为对象返回,而不是内部包含对象的数组。
根据模拟 JSON 响应验证的架构文件:
export const featuresSchema = {
type: 'object',
$ref: 'customDefinitions#/definitions/baseResponseProperties',
properties: {
BAR: { type: 'array', items: { $ref: 'customDefinitions#/definitions/BAR' } }
},
required: ['BAR']
};
我已阅读 Stackoverflow 的建议主题,但找不到与此问题匹配的主题。
感谢您提供的任何帮助。
取决于您未指定的 JSON 架构版本,AJV 默认为 Draft-07 以及您正在使用的
import
语句
几件事:
$ref
的同级。因此,用 $ref
定义的 baseResponseProperties
已被验证,但 BAR
模式被忽略,这就是为什么您没有返回预期的错误。试试这个。
export const featuresSchema = {
allOf: [
{ $ref: 'customDefinitions#/definitions/baseResponseProperties' },
{
type: 'object',
properties: {
BAR: {
type: 'array', items: { $ref: 'customDefinitions#/definitions/BAR' }
}
},
required: ['BAR']
}
]
};
第二个问题是
FOO
仅由 type: ['object', 'null']
定义,并且您定义了 items
关键字。这些 items
永远不会被评估,因为您将模式限制为仅两种定义的类型。
#invalid
FOO: { type: ['object', 'null'], items: { $ref: customDefinitions#/definitions/FOO' } },
#valid
// add array type
FOO: { type: ['object', 'null', 'array'], items: { $ref: customDefinitions#/definitions/FOO' } },
OR
// as an object
FOO: { type: ['object', 'null'], $ref: customDefinitions#/definitions/FOO' },