Workaround for "minContains" & "maxContains" in JSON Schema validation draft-07?

Viewed 368

The latest JSON schema validation release (2019-09) allows one to put conditions (sub-schema) using contains keyword and also how many times that condition can appear in the JSON schema using minContains & maxContains. This functionality is not available in draft-07. Is there any way to attain this without using these keywords? For e.g.

"answers": [
    {
      "id": 1,
      "text": "choice1",
      "isCorrect": true
    },
    {
      "id": 1,
      "text": "choice2",
      "isCorrect": false
    },
    {
      "id": 1,
      "text": "choice3",
      "isCorrect": false
    },
    {
      "id": 1,
      "text": "choice4",
      "isCorrect": false
    }
  ]
}

A condition with contains as below:

"contains":{
  "properties":{
    "isCorrect":{
      "enum":["true"]
     }
  }
}

This checks that isCorrect is true at least once. But if I would like the validation to pass only when the value of isCorrect is true at least twice, how can I achieve that? Any help is appreciated! Thanks.

2 Answers

No there is not, that is why we added the keywords for draft 2019-09. Sorry.

There's not really a way to simulate minContains/maxContains in draft-07. Here's some examples of the closest you can get.

Like "minContains": 2, if you have a fixed number of elements. It's not pretty, but you can enumerate all the possible ways the two items can appear in the array.

{
  "type": "array",
  "maxItems": 4,
  "minItems": 4,
  "anyOf": [
    {
      "items": [
        { "$ref": "#/definitions/isCorrect-true" },
        { "$ref": "#/definitions/isCorrect-true" }
      ]
    },
    {
      "items": [
        { "$ref": "#/definitions/isCorrect-true" },
        true,
        { "$ref": "#/definitions/isCorrect-true" }
      ]
    },
    {
      "items": [
        { "$ref": "#/definitions/isCorrect-true" },
        true,
        true,
        { "$ref": "#/definitions/isCorrect-true" }
      ]
    },
    {
      "items": [
        true,
        { "$ref": "#/definitions/isCorrect-true" },
        { "$ref": "#/definitions/isCorrect-true" }
      ]
    },
    {
      "items": [
        true,
        { "$ref": "#/definitions/isCorrect-true" },
        true,
        { "$ref": "#/definitions/isCorrect-true" }
      ]
    },
    {
      "items": [
        true,
        true,
        { "$ref": "#/definitions/isCorrect-true" },
        { "$ref": "#/definitions/isCorrect-true" }
      ]
    }
  ],
  "definitions": {
    "isCorrect-true": {
      "type": "object",
      "properties": {
        "isCorrect": { "const": true }
      }
    }
  }
}

Like "minContains": 2, except all the true items need to be first in the array.

{
  "type": "array",
  "items": [
    { "$ref": "#/definitions/isCorrect-true" },
    { "$ref": "#/definitions/isCorrect-true" }
  ],
  "definitions": {
    "isCorrect-true": {
      "type": "object",
      "properties": {
        "isCorrect": { "const": true }
      }
    }
  }
}

Like "maxContains": 2, except all the true items need to be first in the array.

{
  "type": "array",
  "items": [
    true,
    true
  ],
  "additionalItems": { "not": { "$ref": "#/definitions/isCorrect-true" } },
  "definitions": {
    "isCorrect-true": {
      "type": "object",
      "properties": {
        "isCorrect": { "const": true }
      }
    }
  }
}

Like "minContains": 2, "maxContains": 2, except all the true items need to be first in the array.

{
  "type": "array",
  "items": [
    { "$ref": "#/definitions/isCorrect-true" },
    { "$ref": "#/definitions/isCorrect-true" }
  ],
  "additionalItems": { "not": { "$ref": "#/definitions/isCorrect-true" } },
  "definitions": {
    "isCorrect-true": {
      "type": "object",
      "properties": {
        "isCorrect": { "const": true }
      }
    }
  }
}
Related