Search code examples
jsonschema

JsonSchema - Should have one of two properties


I'm trying to create a schema for the config file that supports Gaspar.

At the root of the object you need to specify at least one of Models and Controllers (or both).

I found this: https://stackoverflow.com/a/31841897/404459 which seems to answer the question, and gives me something like this (Model and Controllers are really complex objects, but this simplified version proves the point):

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "anyOf": [
        {
            "required": [
                "Models"
            ]
        },
        {
            "required": [
                "Controllers"
            ]
        }
    ],
    "properties": {
        "Models": {
            "type": "string"
        },
        "Controllers": {
            "type": "string"
        },
        "IgnoreAnnotations": {
          "type": "boolean"
        }
    }
}

This all works well and validates in VS Code, but it fails strict validation using the https://www.schemastore.org/json/ validator, which returns:

################ Error message
>> compile              | schemas/json/gaspar.json (draft-07)(FullStrictMode)
>> Error: strict mode: required property "Models" is not defined at "https://json.schemastore.org/gaspar.json#/anyOf/0" (strictRequired)
##############################

I've tried moving the properties inside the anyOf, but it opens up more issues than it solves; maybe that's the right approach but needs more stuff than I'm aware of.

How can I get this to pass strict validation and work?


Solution

  • Adding minProperties: 1 with the anyOf array of required schemas provides the constraint needed to choose at least one of the required properties and any other optional property.

    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "anyOf": [
        {
          "required": [
            "Models"
          ]
        },
        {
          "required": [
            "Controllers"
          ]
        }
      ],
      "minProperties": 1,
      "properties": {
        "Models": {
          "type": "string"
        },
        "Controllers": {
          "type": "string"
        },
        "IgnoreAnnotations": {
          "type": "boolean"
        }
      }
    }
    

    Passing instances

    {
      "Models": ""
    }
    
    {
      "Controllers": ""
    }
    
    {
      "Models": "",
      "IgnoreAnnotations": true
    }
    
    {
      "Controllers": "",
      "IgnoreAnnotations": true
    }
    
    {
      "Models": "",
      "Controllers": "",
      "IgnoreAnnotations": true
    }
    

    Failing instances

    {
      "IgnoreAnnotations": true
    }
    
    {
      "Test": ""
    }
    

    EDIT: To add this type of schema to schemastore.org following the contribution guidelines and their use of Ajv strict mode. You can re-write this schema as follows:

    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "anyOf": [
        {
          "type": "object",
          "required": [
            "Models"
          ],
          "minProperties": 1,
          "properties": {
            "Models": {
              "type": "string"
            },
            "IgnoreAnnotations": {
              "type": "boolean"
            }
          }
        },
        {
          "type": "object",
          "required": [
            "Controllers"
          ],
          "minProperties": 1,
          "properties": {
            "Controllers": {
              "type": "string"
            },
            "IgnoreAnnotations": {
              "type": "boolean"
            }
          }
        }
      ]
    }