Oliver
Oliver

Reputation: 4173

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"]
            }
          }
        }
      }
    }
  }
}

Upvotes: 0

Views: 1010

Answers (2)

Oliver
Oliver

Reputation: 4173

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.

Upvotes: 0

Ether
Ether

Reputation: 53966

You can remove your patternProperties and just collapse that into additionalProperties -- which takes a schema, not just true/false. Because the patternProperties is a wildcard that matches everything, the additionalProperties there adds no value.

Otherwise, aside from the "minProperties": 1 which states that there cannot be zero properties, your definition already allows for optional properties at the top level, and at the "plans" level, all properties are optional as well. Use the required keyword to ensure that a property is actually present:

Reference: https://json-schema.org/understanding-json-schema/reference/object.html

Upvotes: 2

Related Questions