Search code examples
jsonschema

JsonSchema: Optional properties based on value


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

Here is a part of the schema I have built (with some properties removed to make it easier to read):

"Output": {
    "type": "array",
    "items": {
        "type": "object",
        "required": [ "Type" ],
        "additionalProperties": false,
        "properties": {
            "Type": {
                "type": "string",
                "enum": [ "CSharp", "TypeScript" ]
            },
            "ModelNamespaces": {
                "type": "array",
                "description": "CSharp Only",
                "items": {
                    "type": "string"
                }
            },
            "AddInferredNullables": {
                "type": "boolean",
                "description": "TypeScript Only",
            }
        }
    }
},

As you can see, I've set additionalProperties to false as I want miss-spellings to be highlighted. But I'm struggling with making some properties available only when the enum is set:

ModelNamespaces is always optional, but only valid when Type is set to "CSharp"

AddInferredNullables is always optional, but is only valid when Type is set to "TypeScript"

All of the examples I can find seem to be about changing the required status depending on a value; but these properties will always be optional, I would just like it highlighted as incorrect if the Type is "TypeScript" and the user includes ModelNamepaces.

Can this be achieved?


Solution

  • You can use the if, then syntax with JSON Schema draft-07 or newer.

    You'll find the Type schema is defined at the root with the enum constraints, but this keyword must also be redefined in the then schema of the conditional statement. Defining it as a boolean schema is sufficient for the validator to recognize this keyword exists and the constraints at the root will be validated.

    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "properties": {
        "Output": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "Type"
            ],
            "properties": {
              "Type": {
                "type": "string",
                "enum": [
                  "CSharp",
                  "TypeScript"
                ]
              }
            },
            "allOf": [
              {
                "if": {
                  "properties": {
                    "Type": {
                      "const": "TypeScript"
                    }
                  }
                },
                "then": {
                  "properties": {
                    "Type": true,
                    "AddInferredNullables": {
                      "type": "boolean",
                      "description": "TypeScript Only"
                    }
                  },
                  "additionalProperties": false
                }
              },
              {
                "if": {
                  "properties": {
                    "Type": {
                      "const": "CSharp"
                    }
                  }
                },
                "then": {
                  "properties": {
                    "Type": true,
                    "ModelNamespaces": {
                      "type": "array",
                      "description": "CSharp Only",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "additionalProperties": false
                }
              }
            ]
          }
        }
      }
    }
    

    Passing instances:

    {
      "Output": [
        {
          "Type": "TypeScript"    
        }
      ]
    }
    
    {
      "Output": [
        {
          "Type": "TypeScript",
          "AddInferredNullables": true   
        }
      ]
    }
    
    {
      "Output": [
        {
          "Type": "CSharp"
        }
      ]
    }
    
    {
      "Output": [
        {
          "Type": "CSharp",
          "ModelNamespaces": ["something", "anotherThing"]
        }
      ]
    }
    

    Failing instances:

    {
      "Output": [
        {
          "Type": "TypeScript",
          "ModelNamespaces": []
        }
      ]
    }
    
    {
      "Output": [
        {
          "Type": "JavaScript"
        }
      ]
    }
    
    {
      "Output": [
        {
          "Type": "CSharp",
          "AddInferredNullables": true
        }
      ]
    }