0

I want to validate a JSON file using JSON schema, several "properties" should be required depending on what values some other properties have.

Example

  • Having properties "A", "B", "C", and "D"
  • if "A" has value "foo", C is required
  • if "B" has value "foo", D is required
  • if both "A" and "B" each have value "foo", both C and D are required
  • else, nothing is required

I have seen a very helpful answer here: https://stackoverflow.com/a/38781027/5201771 --> there, the author addresses how to solve this problem for the case of a single property (e.g., only "A" has value "foo", so require "C").

However, I currently don't see how to extend that answer to my case, where several properties determine the outcome.

Example Files

for illustration, I supply some files that should pass or fail the validation:

should pass:

{
    "A": "bar"
    "B": "baz"
}
{
    "A": "foo"
    "C": "some value"
}
{
    "A": "bar"
    "B": "foo"
    "D": "some value"
}

should fail:

{
    "A": "foo"
    "B": "foo"
    "D": "some value"
}
S.A.
  • 1,819
  • 1
  • 24
  • 39

1 Answers1

2

You can combine conditionals a number of ways, but combining them with allOf is usually the best way.

{
  "type": "object",
  "properties": {
    "A": {},
    "B": {},
    "C": {},
    "D": {}
  },
  "allOf": [
    { "$ref": "#/definitions/if-A-then-C-is-required" },
    { "$ref": "#/definitions/if-B-then-D-is-required" }
  ],
  "definitions": {
    "if-A-then-C-is-required": {
      "if": {
        "type": "object",
        "properties": {
          "A": { "const": "foo" }
        },
        "required": ["A"]
      },
      "then": { "required": ["C"] }
    },
    "if-B-then-D-is-required": {
      "if": {
        "type": "object",
        "properties": {
          "B": { "const": "foo" }
        },
        "required": ["B"]
      },
      "then": { "required": ["D"] }
    }
  }
}
Jason Desrosiers
  • 22,479
  • 5
  • 47
  • 53
  • That seems to work, thanks! What's surprising to me is that the conditional "required" items from the "allOf" are all integrated into an overall (invisible) "required" list of items (which is what I want, great!). Furthermore, if I already explicitly defined a "required" list of items after "properties", that list gets extended, too (also what I want!). However, it's surprising, because If I instead define "required" multiple times in a JSON schema, the several "required" statements do *not* get integrated: Only one of these "required" gets selected, and the others are discarded. – S.A. Oct 12 '20 at 10:28
  • Each "required" keyword is considered separately when it is evaluated against the data. The nature of the JSON structure means that a keyword can only appear once in its immediate data structure, but if you write the schema in a way that multiple subschemas can apply to the same instance location (such as with if/then, and allOf, etc) then you can use the same keyword in each location so as to have multiple rules. – Ether Oct 13 '20 at 16:16