Ajant
Ajant

Reputation: 158

Json-schema field is present and has value

I have a schema like this:

{
  "$schema": "http://json-schema.org/draft-07/schema#",  
  "type": "object",
  "properties": {
    "foo": {
      "enum": [
        "foo1",
        "foo2"
      ]
    },
    "bar": {
      "type": "number"
    },
}

I want bar to be required if foo is present and if it has value "foo1", otherwise it should be forbidden. I was trying something like:

"if": {
    "properties": {
      "foo": {
        "const": "foo1"
      }
    }
  },
  "then": {
    "required": [
      "bar"
    ]
  },
  "else": {
    "not": {
      "required": [
        "bar"
      ]
    }
  }

However, what happens is if foo is not present, then bar is required and I don't want that. It's as if absence of the field is interpreted as true by the if statement. Is there a way to make one field required only if another optional field is present and has specific value? Something like:

"if": {
  allOf: [
    {
      "properties": {
        "foo": {
          "const": "foo1"
        }
      }
    },
    {
      "contains": "foo"
    }
  ]
}
"then": {
  "required": [
    "bar"
  ]
},
"else": {
  "not": {
    "required": [
      "bar"
    ]
  }
}

By the way I've found many similar questions here, but none where foo is not required.

Upvotes: 0

Views: 1388

Answers (2)

Ajant
Ajant

Reputation: 158

After few more hours I came up with a solution, which I'm going to post here, because it works for earlier versions of json schema, where if/then/else are not available, so someone might need it if they are unable to upgrade, but I accepted Relequestual's answer, because his solution is more elegant for those who have latest version at their disposal

"oneOf":
  [
    {
      "not": {"required": ["foo", "bar"]}
    },
    {
      "required": ["foo"],
      "anyOf": [
        {
          "properties":{
            "foo":{"enum": ["foo1"]}
          },
          "required": ["bar"]
        },
        {
          "properties":{
            "foo": {"not": {"enum": ["foo1"]}}
          },
          "not": {"required": ["bar"]}
        }
      ]}
  ]

Upvotes: 0

Relequestual
Relequestual

Reputation: 12295

The values of the if/then/else keywords are schemas themselves. What happens if you take the schema value of your if keyword on its own?

What you'll find is, it will validate an empty object successfully without error.

properties only applies subschemas to instance locations where the keys match. If your object has no foo property, you're not doing any validation on the object.

You need to add required to your if statement for this to work how you expect.

"if": {
    "properties": {
      "foo": {
        "const": "foo1"
      }
    },
    "required": ["foo"]
  }

See it in action here: https://jsonschema.dev/s/L0rlG

Upvotes: 2

Related Questions