Anbarasan
Anbarasan

Reputation: 1207

Json Schema - not required is not working

I have a case where i am validating the required properties conditionally.

"not required" is not working as expected.

If 'profile' as profile1 then 'rate', 'trick' and 'tag' fields are required and 'code', 'name' and 'type' should not be present.

If 'profile' as profile2 then 'code' is required, and 'rate', 'tag', and 'trick' are not required.

if 'profile' is profile3 then 'rate', 'tag', 'trick', 'code', 'name' and 'type' are not required.

I am using schema draft version 4

Schema

{
  "type": "object",
  "properties": {
    "id": { "type": "integer" },
    "url": { "type": "string" },
    "profile": { "type": "string" },
    "rate": { "type": "string" },
    "trick": { "type": "boolean" },
    "tag": { "type": "string" },
    "type": { "type": "string" },
    "name": { "type": "string" },
    "code": { "type": "string" }
  },
  "additionalProperties": false,
  "required": [ "url", "profile" ],
  "oneOf": [
    {
      "properties": { "profile": { "enum": [ "profile1" ] } },
      "not": { "required": ["type", "name", "code"] }
    },
    {
      "properties": { "profile": { "enum": [ "profile2" ] } },
      "allOf": [
        { "required": [ "code" ] },
        { "not": { "required": ["rate", "tag", "trick"] } }
      ]
    },
    {
      "properties": { "profile": { "enum": ["profile3"] } },
      "not": { "required": ["rate", "trick", "tag", "type", "name", "code"] }
    }
  ]
}

Valid Inputs

{
  "id": 1,
  "url": "url",
  "profile": "profile2",
  "type": "",
  "name": "",
  "code": ""
}
{
  "id": 1,
  "url": "url",
  "profile": "profile3"
}
{
  "id": 1,
  "url": "url",
  "profile": "profile1",
  "rate": "",
  "trick": false,
  "tag": ""
}

Invalid Inputs

{
  "url": "url",
  "profile": "profile3",
  "code": ""
}

Upvotes: 2

Views: 1211

Answers (2)

Aniket Kariya
Aniket Kariya

Reputation: 1980

I do not know whether this is a bug in json schema itself or the language server. somehow not required only seems to work with the first item in the array. This worked for me:

....
"allOf": [
    {"not": {"required": ["type"]}},
    {"not": {"required": ["name"]}},
    {"not": {"required": ["code"]}}
]
....

Upvotes: 1

Relequestual
Relequestual

Reputation: 12335

I can see how you arrived at this approach, and you could make it work, but it's not the best approach.

The not keyword inverts the assertion result of the value subschema.

If you take anyOf[2].not schema...

{ "required": ["rate", "trick", "tag", "type", "name", "code"] }

This means, as I'm sure you know, all of those properties are required.

not then inverts the result of applying that subschema.

Because in your object example which you expect to fail validation, it only has codeout of that array, then it doesn't meet the required constraint.

You could make it not > anyOf > [required > rate, required > trick... etc having many subschemas, but that would be a little ugly.

In stead, you could use an alternative approach, and specify what is ALLOWED...

Your anyOf would then look like this (demo: https://jsonschema.dev/s/zG9GF):

"anyOf": [
    false,
    false,
    {
      "properties": {
        "profile": {
          "const": "profile3",
          "id": true
        }
      },
      "additionalProperties": false
    }
  ]

You may find it more idiomatic to use if/then/else keywords from draft-07, and then you can use allOf and set the else value to false if you don't want to have a top level enum for profile.

Upvotes: 1

Related Questions