Search code examples
jsonjsonschemajson-schema-validator

How to write a valid JSON Schema for a document with only optional elements


I use JSON Schema to validate YAML and JSON configuration files. In one configuration file are all elements optional. But only is a limited set of elements is allowed.

What do I have to change in the given schema below, so that an empty file/document in case of JSON is also valid?

{
  "$id": "https://snafu.com/api/service/publishing-mechanism/config-delta/1.0.0",
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "description": "....",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "plans": {
      "type": "object",
      "additionalProperties": false,
      "minProperties": 1,
      "patternProperties": {
        "^.*$": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "description": {
              "type": "string"
            },
            "validation": {
              "type": "string",
              "enum": ["auto", "manual"]
            },
            "security": {
              "type": "string",
              "enum": ["api_key"]
            }
          }
        }
      }
    }
  }
}

Solution

  • So, after quite some time, here is the solution which is working for my project in production.

    {
      "$id": "https://snafu.com/api/service/publishing-mechanism/config-delta/1.0.0",
      "$schema": "https://json-schema.org/draft/2019-09/schema",
      "description": "....",
      "$defs": {
        "empty": {"type": "null"}
      },
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "plans": {
          "oneOf": [
            {
              "type": "object",
              "additionalProperties": false,
              "patternProperties": {
                "^.+$": {
                  "oneOf": [
                    {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "description": {
                          "minLength": 1,
                          "type": "string"                  
                        },
                        "security": {
                          "enum": ["api_key"],
                          "type": "string"
                        }
                      }
                    },
                    { "$ref": "#/$defs/empty" }
                  ]
                }
              }
            },
            { "$ref": "#/$defs/empty" }
          ]
        }
      }
    }
    

    Here I use oneOf to have two mutually exclusive subschemas. One of the is all the possible properties, where one of them is required.

    The second subschema has null as type. Therefore the only acceptable value for this schema is null.