ajv icon indicating copy to clipboard operation
ajv copied to clipboard

Do not short-circuit anyOf with allErrors option

Open epoberezkin opened this issue 7 years ago • 2 comments

Problem

Allow some advanced logic for data validation based on annotation keywords etc.

Solution

Do not short-circuit anyOf keyword with allErrors: true option Provide a separate option to override this behaviour (e.g. shortCircuit) that would override the default behaviour for allOf any anyOf.

Logic when keywords are short-circuited after the change (changed behaviour in bold):

allErrors →
shortCircuit ↓
false true
undefined allOf: short
anyOf: short
allOf: full
anyOf: full
false allOf: full
anyOf: full
allOf: full
anyOf: full
true allOf: short
anyOf: short
allOf: short
anyOf: short

epoberezkin avatar Jan 03 '18 13:01 epoberezkin

oneOf can never short-circuit, if/then/else should always short-circuit, so they are not affected.

epoberezkin avatar Jan 03 '18 13:01 epoberezkin

Why do I get errors with this code? Using anyOf or oneOf - no difference...

const Ajv = require("ajv");

ajv = new Ajv({
  removeAdditional: true,
  useDefaults: true,
  coerceTypes: "array",
  allErrors: true,
});

var schema = {
  type: "object",
  required: ["service", "receipt", "credentials"],
  additionalProperties: false,
  properties: {
    service: {
      type: "string",
    },
    receipt: {
      oneOf: [
        {
          type: "object",
          required: ["data", "productId", "os"],
          additionalProperties: false,
          properties: {
            data: {
              type: "object",
              required: ["productId", "purchaseToken", "packageName"],
              additionalProperties: false,
              properties: {
                productId: {
                  type: "string",
                },
                purchaseToken: {
                  type: "string",
                },
                packageName: {
                  type: "string",
                },
              },
            },
            productId: {
              type: "string",
            },
            os: {
              enum: ["android"],
            },
          },
        },
        {
          type: "object",
          required: ["data", "productId", "os"],
          additionalProperties: false,
          properties: {
            data: {
              type: "object",
              required: ["transactionId", "receiptData"],
              additionalProperties: false,
              properties: {
                transactionId: {
                  type: "string",
                },
                receiptData: {
                  type: "string",
                },
              },
            },
            productId: {
              type: "string",
            },
            os: {
              enum: ["ios", "tvos"],
            },
          },
        },
      ],
    },
    credentials: {
      type: "object",
      required: ["username", "password"],
      additionalProperties: false,
      properties: {
        username: {
          type: "string",
          minLength: 3,
        },
        password: {
          type: "string",
          minLength: 1,
        },
      },
    },
  },
};

var data = {
  service: "service name",
  receipt: {
    productId: "asd",
    os: "ios",
    data: {
      transactionId: "asd",
      receiptData: "asd",
    },
  },
  credentials: {
    username: "[email protected]",
    password: "donuts",
  },
};

var validate = ajv.compile(schema);
// console.log(validate.source.validateCode)
console.log(validate(data));
console.log(validate.errors);

I'm using the allErrors: true because I want to get all errors not just the first one. But (in my opinion) the code above should not have any errors ...

can this be setup to report all errors if schema fails but no errors and succeed with anyOf/oneOf?

pkyeck avatar May 18 '23 09:05 pkyeck