Search code examples
jsonschema

How to evaluate multiple schemas with the same required keys using dependentSchema in JSON schema?


If I was expecting either one of these three objects without allowing any additional properties, how would I evaluate this in JSON schema? In it, a fruit can either be a real fruit, in which case it can contain the required "fruit" keyword alongside an optional keyword for its "weight", or a fruit can be a fake fruit, which requires the "plastic" keyword to describe what type of plastic it uses.

{
    "fruit": "apple"
}

or

{
    "fruit": "apple",
    "weight": 0.13145
}

or

{
    "fruit": "apple",
    "plastic": "polypropolene"
}

If I try to use the dependentSchema like so, plastic fruits obviously fail as it tries to match it against both schema since it also contains the "fruit" key. I can't find anywhere that tells me how to use if then statements to match schema depending on their keys, only their values, so I assume I have to figure out some way to make dependent schema work, right?

{
  "type": "array",
  "items": {
    "type": "object",
    "dependentSchemas": {
      "fruit": {
        "type": "object",
        "additionalProperties": false,
        "required": "fruit",
        "properties": {
          "fruit": { "type": "string" },
          "diameter": { "type": "number" }
        }
      },
      "plastic": {
        "type": "object",
        "additionalProperties": false,
        "required": ["fruit", "plastic"],
        "properties": {
          "fruit": { "type": "string" },
          "plastic": { "type": "string" }
        }
      },
      "meat": { "$ref": "#/$defs/meat" },
      "bread": { "$ref": "#/$defs/bread" }
    }
  }
}

Solution

  • You can use oneOf for the second property

    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "required": ["fruit"],
      "additionalProperties": false,
      "properties": {
        "fruit": {
          "type": "string"
        },
        "weight": true,
        "plastic": true
      },
      "oneOf": [
        { 
           "type": "object",
           "required":["weight"],
           "properties": {
             "weight": {
               "type": "number"
             }
           }
        },
        {
           "type": "object",
           "required": ["plastic"],
           "properties": {
             "plastic": {
               "type": "string"
             }
           }
         }
      ]
    }