3
votes

I need to validate a json object that always have 2 properties:

  • type
  • name

type can be "A", "B" or "C",

when type is "A", also the property "foo" is required and no additional properties are allowed.

OK:

{
    "type": "A",
    "name": "a",
    "foo": "a",
}

Not OK:

{
    "type": "A",
    "name": "a",
    "foo": "a",
    "lol": "a"
}

when type is "B", the property "bar" is required and no additional properties are allowed.

when type is "C", the property "bar" is required and optionally also "zen" property can be present.

OK:

{
    "type": "C",
    "name": "a",
    "bar": "a",
    "zen": "a"
}

{
    "type": "C",
    "name": "a",
    "bar": "a",
}

Not OK:

{
    "type": "C",
    "name": "a",
    "bar": "a",
    "lol": "a" 
}

Unfortunately the outstanding answer to this question partially cover my case, however I did not managed to build a jsonschema that works for me.

edit:

Here is what I tried.

{
    "$schema": "http://json-schema.org/draft-04/schema",
    "type": "object",
    "properties": {
        "type": {
            "type": "string",
            "enum": ["A", "B", "C"]
        },
        "name": {"type": "string"},
        "foo": {"type": "string"},
        "bar": {"type": "string"},
        "zen": {"type": "string"},
    },
    "anyOf": [
        {
            "properties": {"type": {"enum": ["A"]}},
            "required": ["foo"],
        },
        {
            "properties": {"type": {"enum": ["B"]}},
            "required": ["bar"],
        },
        {
            "properties": {"type": {"enum": ["C"]}},
            "required": ["bar"],
        },
    ]
}

My problem is that setting the field "additionalProperties" to false inside the objects in "anyOf" does not give me the expected result.

for instance the following json pass the validation despite it has the additional property "lol"

{
    "type": "A",
    "name": "a",
    "foo": "a",
    "lol": "a"
}
2
I updated my post to include the example I tried and the reason why this solution does not work for mecunfusu

2 Answers

1
votes

The following schema worked for me on your example. Hopefully this helps others. Trick was to use a combination of additionalProperties and maxProperties, with required in the right places:

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "type": "object",
  "properties": {
    "type": {
      "type": "string",
      "enum": [
        "A",
        "B",
        "C"
      ]
    },
    "name": {
      "type": "string"
    },
    "foo": {
      "type": "string"
    },
    "bar": {
      "type": "string"
    },
    "zen": {
      "type": "string"
    }
  },
  "required": [
    "name",
    "type"
  ],
  "allOf": [
    {
      "if": {
        "properties": {
          "type": {
            "const": "A"
          }
        }
      },
      "then": {
        "required": [
          "foo"
        ],
        "maxProperties": 3
      }
    },
    {
      "if": {
        "properties": {
          "type": {
            "const": "B"
          }
        }
      },
      "then": {
        "required": [
          "bar"
        ],
        "maxProperties": 3
      }
    },
    {
      "if": {
        "properties": {
          "type": {
            "const": "C"
          }
        }
      },
      "then": {
        "required": [
          "bar"
        ],
        "maxProperties": 4
      }
    }
  ],
  "additionalProperties": false
}
0
votes

JSON Schema is a constraint system where the constraints of each subschema are evaluated separately. That means that "additionalProperties" can only "see" the "properties" or "patternProperties" within the same immediate schema object.

Additionally, it cannot "see" properties based on "required", only on "properties" and "patternProperties".

As far as I can tell, if you were setting "additionalProperties": false inside each branch of the anyOf, none of this should work as the only allowed property would be "type". If you did that and it is allowing properties other than "type", then I would want to know what implementation you are using.