Home > Net >  jsonSchema attribute conditionally required in array
jsonSchema attribute conditionally required in array

Time:12-02

I would like to define and validate such JSON schema with ajv :

    {
       "defaults": {
           "foo": {
               "bar": "Default value 1",
               "baz": "Default value 2"
           }
       },
      "entries": [
         {
            "foo": {
                "bar": "Overwritten value"
            },
            "other": 123
         }
      ]
    }

With the following restrictions :

  • If defaults.foo.bar is present, then entries[x].foo.bar is not mandatory (user can provide it, if (s)he wants )
  • If defaults.foo.bar is not present, then entries[x].foo.bar is mandatory
  • If defaults.foo.baz is present, then entries[x].foo.baz is not mandatory (user can provide it, if (s)he wants )
  • If defaults.foo.baz is not present, then entries[x].foo.baz is mandatory
  • defaults is optional
  • entries is mandatory (even if empty)

I understand I probably have to use If-Then-Else structure, but it is unclear for me how to do it as user can provide as many "entries" wanted and examples I saw don't have this parent-child relationship.

Thanks in advance

CodePudding user response:

The trick to describing this kind of constraint is that you have to write a bunch of nested schemas to describe the constraint from the top level. In JSON Schema, properties are always optional unless declared to be required. So, you don't need to write assertions for cases where things can be optional, just the ones where things are required.

The following schema shows how to express the requirement: "If defaults.foo.bar is not present, then entries[x].foo.bar is mandatory". The "baz" requirement would follow the same pattern and the reset of the requirements either require no code or are trivial, so I expect you can figure out the rest.

{
  ... describe the basic structure ...

  "allOf": [
    {
      "if": { "$ref": "#/$defs/defaults.foo.bar-is-not-present" },
      "then": { "$ref": "#/$defs/entries[x].foo.bar-is-required" }
    },
    {
      "if": { "$ref": "#/$defs/defaults.foo.baz-is-not-present" },
      "then": { "$ref": "#/$defs/entries[x].foo.baz-is-required" }
    }
  ],

  "$defs": {
    "defaults.foo.bar-is-not-present": {
      "type": "object",
      "properties": {
        "defaults": {
          "type": "object",
          "properties": {
            "foo": {
              "not": { "required": ["bar"] }
            }
          },
          "required": ["foo"]
        }
      },
      "required": ["defaults"]
    },

    "entries[x].foo.bar-is-required": {
      "type": "object",
      "properties": {
        "entries": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "foo": { "required": ["bar"] }
            },
            "required": ["foo"]
          }
        }
      },
      "required": ["entries"]
    }
  },

  ... Filling in the missing definitions ...
}
  • Related