ajv schema validation fails when working with array types

51 views Asked by At

I'm using ajv to validate a JSON instance using a fairly simple schema, but that is failing on the array type with the following message:

"this must be equal to one of the allowed values"

Problem is, my value is one of the allowed values. This seems like such a simple problem but I've not yet found a solution. Here's my code:

const Ajv = require("ajv");
const ajv = new Ajv();

const schema = {
  type: "object",
  properties: {
    count: { type: "integer" },
    name: { type: "string" },
    bass: {
      type: "array",
      items: {
        type: "string",
      },
      enum: ["Ambush Custom Bass", "MTD", "Ken Smith", "Sadowsky"],
    },
  },
  required: ["count"],
};

const validate = ajv.compile(schema);

const data = {
  count: 1,
  name: "Andy",
  bass: ["MTD"],
};

const valid = validate(data);

console.log("valid: ", valid);

if (!valid) console.log(validate.errors);

Thanks for your help.

2

There are 2 answers

0
andyengle On

Well, as usual, I had to first ask the question to the masses so I could figure it out on my own. I don't know if it's the right way, but here's what I did:

First, remove the keyword for enum, like so:

ajv.removeKeyword("enum");

Next, add the enum keyword back, and with it, your custom validation function:

ajv.addKeyword({
  keyword: "enum",
  validate: (schema, data, value, other) => {
    // custom validation goes here
  }
});

Finally, I found that the validate function here doesn't give you the option of adding detailed error messaging (or, if it does, I couldn't figure out how to do it), so I created an error array, then pushed entries into that array, with each entry being an object that includes other.instancePath. Then when iterating through the validation.errors array, I combine the more detailed messaging with ajv's errors so I can have custom error messaging along with the error details ajv provides. I hope that makes sense; if not, give me a holler, and I'll further explain.

0
TBA On

there is actually a much simpler solution: add the enum values under items field:

...
const schema = {
  type: "object",
  properties: {
    count: { type: "integer" },
    name: { type: "string" },
    bass: {
      type: "array",
      items: {
        type: "string",
        enum: ["Ambush Custom Bass", "MTD", "Ken Smith", "Sadowsky"],
      },
    },
  },
  required: ["count"],
};
...

This way you don't need to remove/add enum keyword