AJV 忽略嵌套引用对象中属性的“必需”规则

问题描述 投票:0回答:1

我有一个类,允许我使用 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"
    }]
}

预期结果:应该抛出一个错误,表明需要删除的属性。

实际结果:验证成功。

故障排除:

  1. 从模拟 JSON 响应的根中删除了属性,以确保 AJV 在缺少所需属性时正确出错。是的。

  2. _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 validation schema ajv
1个回答
0
投票

取决于您未指定的 JSON 架构版本,AJV 默认为 Draft-07 以及您正在使用的

import
语句

几件事:

  • 您的架构定义将被部分忽略,因为在 JSON 架构的旧草案版本中您不能有
    $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' },


© www.soinside.com 2019 - 2024. All rights reserved.