Swatcat
Swatcat

Reputation: 37

JSON Schema Conditional Statements

I am trying to validate what I thought was a simple JSON schema as a configuration file for my Python application, it's a list of header key/value pairs, the only complication is that if the 'Type' field is set to 'AnyValue' then the value key is not required.

Here is the schema as it is:

{
    "definitions":
    {
        'KeyEntry':
        {
             "properties":
             {
                'Type': {"type" : "string"},
                'Key': {"type": "string"}
             },
             "required": ['Type', 'Key'],
            "anyOf":
            [
                {
                    "if":
                    {
                        "properties": {'Type': {"const": 'ExactValue'}}
                    },
                    "then":
                    {
                        "properties":
                        {
                            'Value': {"type": "string"}
                        },
                        "required": ['Type', 'Key', 'Value'],
                        "additionalProperties": false
                    }
                },
                {
                    "if":
                    {
                        "properties": {'Type': {"const": 'AnyValue'}}
                    },
                    "then":
                    {
                        "required": ['Type', 'Key'],
                        "additionalProperties": false
                    }
                }
            ]
        }
    },

    "type": "object",
    "properties":
    {
        'Keys':
        {
            "type": "array",
            "items": {"$ref": "#/definitions/KeyEntry"}
        }
    },
    "required": ['Keys']
}

Most of the validation works, except if I add extra values, even though I have set "additionalProperties": false throughout the schema.

Here is an example where extra values are accepted:

{
    "Keys": [

        {
            "Type": "AnyValue",
            "Key": "Version",
            "Y": "Yes",
            "N": "No",
        }
    ]
}

Please can someone help explain where I have gone wrong and how I should correct it, please?

Upvotes: 0

Views: 2364

Answers (1)

Relequestual
Relequestual

Reputation: 12295

additionalProperties draft-07...

Validation with "additionalProperties" applies only to the child values of instance names that do not match any names in "properties", and do not match any regular expression in "patternProperties".

This means that additionalProperties is only aware of keywords which appear in properties or that match the regex from patternProperties. Using additionalProperties with required without properties is going to create a dud schema (nothing will pass validation).

In stead, you can separate the concerns into what you actually want...

  • You want type, key, and value, to all be strings. One of...
  • If type is AnyValue, then require type and key only.
  • If type is ExactValue, then require type, key, and value.

This is also easier to understand. Here's a live demo with your data.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "KeyEntry": {
      "properties": {
        "Type": {
          "type": "string"
        },
        "Key": {
          "type": "string"
        },
        "Value": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": [
        "Type",
        "Key"
      ],
      "anyOf": [
        {
          "if": {
            "properties": {
              "Type": {
                "const": "ExactValue"
              }
            }
          },
          "then": {
            "required": [
              "Type",
              "Key",
              "Value"
            ]
          },
          "else": false
        },
        {
          "if": {
            "properties": {
              "Type": {
                "const": "AnyValue"
              }
            }
          },
          "then": {
            "required": [
              "Type",
              "Key"
            ]
          },
          "else": false
        }
      ]
    }
  },
  "type": "object",
  "properties": {
    "Keys": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/KeyEntry"
      }
    }
  },
  "required": [
    "Keys"
  ]
}

Upvotes: 1

Related Questions