47

Is it possible to set up a JSON schema that still allows for additionalProperties but does not match if a very particular property name is present? In other words, I need to know if it's possible to have the exact opposite of the required declaration.

Schema:

{
    "type": "object",
    "properties": {
        "x": { "type": "integer" }
    },
    "required": [ "x" ],
    "ban": [ "z" ] // possible?
}

Match:

{ "x": 123 }

Match:

{ "x": 123, "y": 456 }

Do not match:

{ "x": 123, "y": 456, "z": 789 }
M Miller
  • 5,364
  • 9
  • 43
  • 65

5 Answers5

56

What you want to do can be achieved using the not keyword. If the not schema validates, the parent schema will not validate.

{
    "type": "object",
    "properties": {
        "x": { "type": "integer" }
    },
    "required": [ "x" ],
    "not": { "required": [ "z" ] }
}
Jason Desrosiers
  • 22,479
  • 5
  • 47
  • 53
  • 6
    Not required does not mean "must not be present". – jruizaranguren Jun 09 '15 at 06:52
  • 1
    @jruizaranguren, are you trying to say this answer is wrong? I can expand on my explanation if it is not clear why this schema answers the question. – Jason Desrosiers Jun 10 '15 at 07:33
  • 2
    You are right. I'm wrong. Not need to expand explanation. – jruizaranguren Jun 10 '15 at 07:36
  • 5
    While correct in JSON schema, I share @jruizaranguren's confusion about the logic. (Not the only place in JSON schema, sadly. :/) – Raphael Jul 05 '18 at 15:40
  • I also think it's syntactically confusing (although it works to avoid the presence of the parameter). In the other hand, the validators I have used does not provides a clear error in such situations. – adripanico Oct 04 '19 at 09:11
  • @adripanico - from when originally asked, wouldn't have worked, but with Draft 6+ a combination of "not": {"propertyNames": {"enum": ["bad", "properties"]}} works well with Validators, providing specific invalid property names in returned errors. – RealBlueSky Feb 14 '20 at 19:46
  • 1
    @JasonDesrosiers What jruizaranguren tries to imply is that `not required` means `even if it is there it doesn't matter`. That's not a problem with your answer, but the sense of the JSON schema syntax. `"not": { "required": [ "z" ] }` doesn't mean the same in natural english.. – Romeo Sierra Feb 28 '20 at 05:16
  • Hi, I'm trying to achieve something similar to what OP asked. I want to "ban" another property besides z. If I add it to the not required array: "not" : {"required" : ["z","y"]} and in the json body I sent only the properties x and z, it validates: Is this the expected behavior? – jrf Apr 06 '20 at 18:27
  • 3
    @jrf It's funny you ask that, because I just answered that question a couple hours ago and it's not a common question. The "What's up with `required`-`not` section should answer your question https://stackoverflow.com/a/61062869/1320693 – Jason Desrosiers Apr 06 '20 at 18:35
  • Wow thanks @JasonDesrosiers! I've been looking about these topics in SO for quite a few days now, but haven't found much. That questions is exactly what I'm trying to do... I thought I was stretching the capabilities of json-schema too much, but I guess I'm not the only one! Thanks! – jrf Apr 06 '20 at 18:41
46

There is a simpler approach. Define that if x is present it must not satisfy any schema. By reduction to absurdity x can not be present:

{
    "properties" : {
        "x" : {
            "not" : {}

        }
    }
}

Update 2020/04/16: As pointed out by @Carsten in a comment, from draft version 05 and above, the proposed schema can be simplified as follows:

{
    "properties": {
       "x": false
    }
}
jruizaranguren
  • 12,679
  • 7
  • 55
  • 73
  • The most convenient and non-confusing answer for me. The particular pro of it is that it is placed inside `properties` keyword, along with another properties. – 1valdis Dec 29 '18 at 09:44
  • IMO it's not an answer to this particular question, but it's really good. – kris_IV Dec 05 '19 at 12:34
  • 3
    A short-hand for `”x”: { ”not”: {} }` in newer draft versions would be `”x”: false`. – Carsten Apr 15 '20 at 16:53
  • @kris_IV Why don't you think this answers the OP's question? This meets the criteria of "must not exist" precisely. – silkfire Oct 22 '21 at 09:47
  • 1
    For anyone using it with AJV: if you want custom error messages with AJV validator for explaining why it is not allowed, then you cannot weave that into the shorthand syntax, but the classical "not" method works. – seekingtheoptimal Dec 06 '21 at 12:18
  • Works perfectly, with networknt, json-schema-validator however, gives a cryptic error '[Boolean schema false is not valid]' – Ironluca Feb 25 '22 at 18:38
6

I solved the issue by banning additional properties via "additionalProperties": false but using patternProperties to allow any property name except the banned one.

{
    "type": "object",
    "properties": {
        "x": { "type": "integer" }
    },
    "required": [ "x" ],
    "patternProperties": {
        "^(?!^z$).*": {}
    },
    "additionalProperties": false
}
M Miller
  • 5,364
  • 9
  • 43
  • 65
5

To specify the absence of a field, you can expect it's type to be null.

{
    "type": "object",
    "properties": {
        "x": { "type": "integer" },
        "z": { "type": "null" }

    },
    "required": [ "x" ]
}
Tomás Senart
  • 1,403
  • 1
  • 12
  • 15
-2

You can have type null for that particular property :

 z : {
"type": "null"
}
swarnim gupta
  • 213
  • 1
  • 5
  • Works, however, with networknt jason-schema-validator, gives kind of ugly error: [$.: array found, unknown expected]. But it is better than 'Boolean schema false is not valid '(refer: comment above) – Ironluca Feb 25 '22 at 18:41