0

I am creating a JSON schema and I have a boolean variable in the schema. When this boolean is true, I want some properties of the schema to be required. When this boolean is false, I want other properties of the schema to be required.

Ex (pretend like JSON has comments with //):

{
   "my_boolean": false,        // boolean which determines which schema to use
   "field1": "someString"      // required when my_boolean is false, optional when true
   "field2": "someOtherString" // required when my_boolean is true, optional when false
}

I assume I want some sort of anyOf specification, but I can't think of how to define "when true do this when false do that". I came across this SO post and implication is exactly what I want, but the library I'm using for validation only supports up to JSON schema draft 04.

Ethan Harlig
  • 756
  • 1
  • 7
  • 22
  • With draft-4, you cannot do conditional logic, however you're on the right track in terms of using `*of` keywords. You want `oneOf`. It takes an array of schemas. Try writing two separate schemas for your two cases, then wrap them in a `oneOf`. If that doesn't help, I'm happy to help flesh out the method later, but I can't do that today. – Relequestual Sep 12 '19 at 08:14
  • Thanks for the response! My concern with `oneOf` is that one of the two schemas is a subset of the other. So for example, when `my_boolean` is false, __at least__ `field1` and `field2` must be provided. When `my_boolean` is true, __at least__ `field1`, `field2`, `field3`, and `field4` must be provided. I think this makes it difficult because simply having `required: [field1, field2]` isn't enough since when `my_boolean` is true, validation should fail, but I can't think of how else to do this without conditional logic. – Ethan Harlig Sep 12 '19 at 17:28
  • With each schema in the array, you need to fully express the condition and requirements in one go. It is not intuitive to write or for others to read. I strongly suggest you use a different library that supports a more modern version of JSON Schema. – Relequestual Sep 12 '19 at 20:45

1 Answers1

1

The implication pattern works with draft-04. The only keyword in the example from the SO answer you referenced that isn't available in draft-04 is const. You can use a singleton enum instead ("const": "foo" becomes "enum": ["foo"]).

Your example would look like the following. It's quite verbose, but it does what you need.

{
  "type": "object",
  "properties": {
    "my_boolean": { "type": "boolean" },
    "field1": { "type": "string" },
    "field2": { "type": "string" }
  },
  "allOf": [
    { "$ref": "#/definitions/my_boolean-true-implies-field1-required" },
    { "$ref": "#/definitions/my_boolean-false-implies-field2-required" }
  ],
  "definitions": {
    "my_boolean-true-implies-field1-required": {
      "anyOf": [
        { "not": { "$ref": "#/defintions/my_boolean-true" } },
        { "required": ["field1"] }
      ]
    },
    "my_boolean-false-implies-field2-required": {
      "anyOf": [
        { "not": { "$ref": "#/defintions/my_boolean-false" } },
        { "required": ["field2"] }
      ]
    },
    "my_boolean-true": {
      "properties": {
        "my_boolean": { "enum": [true] }
      },
      "required": ["my_boolean"]
    },
    "my_boolean-false": {
      "properties": {
        "my_boolean": { "enum": [false] }
      },
      "required": ["my_boolean"]
    }
  }
}
Jason Desrosiers
  • 22,479
  • 5
  • 47
  • 53