3

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"
}
cunfusu
  • 97
  • 1
  • 9
  • I updated my post to include the example I tried and the reason why this solution does not work for me – cunfusu Oct 09 '17 at 15:26

2 Answers2

1

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.

Henry Andrews
  • 663
  • 3
  • 6
  • so basically the only way to implement the rigid schema I need is to use anyOf with the list of schema that validate exactly what i need, I wanted to reuse some properties but seems that this is not possible. – cunfusu Oct 11 '17 at 09:53
  • In draft-06, you can do some re-use with `propertyNames`, although it's not incredibly concise. – Henry Andrews Oct 12 '17 at 23:58
1

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
}
Irv
  • 540
  • 4
  • 13