Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON Schema: validate a number-or-null value

Is there a way to enable a JSON schema property to be either a number or null?

I am building an API which contains a heading attribute. Can be a number between 0 (inclusive) and 360 (exclusive), or null, so the following inputs are OK:

{"heading": 5} {"heading": 0} {"heading": null} {"heading": 12} {"heading": 120} {"heading": null} 

And the following inputs are erroneous:

{"heading": 360} {"heading": 360.1} {"heading": -5} {"heading": false} {"heading": "X"} {"heading": 1200} {"heading": false} 

Addendum:

anyOf is clearly the right answer. Adding the full schema for clarity.

Schema

{     "$schema": "http://json-schema.org/draft-04/schema#",     "type": "object",     "additionalProperties": false,     "properties": {       "heading": {         "anyOf": [           {"type": "number"},           {"type": "null"}         ]       }     } } 
like image 456
Adam Matan Avatar asked Mar 21 '14 17:03

Adam Matan


People also ask

How do I allow null values in JSON?

To include null values in the JSON output of the FOR JSON clause, specify the INCLUDE_NULL_VALUES option. If you don't specify the INCLUDE_NULL_VALUES option, the JSON output doesn't include properties for values that are null in the query results.

How does JSON Schema validate JSON data?

The simplest way to check if JSON is valid is to load the JSON into a JObject or JArray and then use the IsValid(JToken, JsonSchema) method with the JSON Schema. To get validation error messages, use the IsValid(JToken, JsonSchema, IList<String> ) or Validate(JToken, JsonSchema, ValidationEventHandler) overloads.

Does JSON have schema validation?

JSON Schema Validation: The JSON Schema Validation specification is the document that defines the valid ways to define validation constraints. This document also defines a set of keywords that can be used to specify validations for a JSON API.


2 Answers

In draft-04, you would use the anyOf directive:

{   "anyOf": [     {       "type": "number",       "minimum": 0,       "maximum": 360,       "exclusiveMaximum": true     },     {       "type": "null"     }   ] } 

You could also use "type": ["number", "null"] as Adam suggests, but I think anyOf is cleaner (as long as you use a draft-04 implementation), and ties the minimum and maximum declaration to the number explicitly.

Disclaimer: I don't know anything about the python implementation, my answer is about json schema.

like image 107
fiddur Avatar answered Sep 28 '22 07:09

fiddur


The trick is using a type array. Instead of:

"type": "number" 

Use:

"type": ["number", "null"] 

The following code enforces a number-or-null policy, plus numerical restrictions if the value is a number:

from jsonschema import validate from jsonschema.exceptions import ValidationError import json  schema=json.loads("""{   "$schema": "http://json-schema.org/schema#",   "description": "Schemas for heading: either a number within [0, 360) or null.",   "title": "Tester for number-or-null schema",   "properties": {     "heading": {       "type": ["number", "null"],       "exclusiveMinimum": false,       "exclusiveMaximum": true,       "minimum": 0,       "maximum": 360     }   } }""")  inputs = [ {"heading":5}, {"heading":0}, {"heading":360}, {"heading":360.1}, {"heading":-5},{"heading":None},{"heading":False},{"heading":"X"}, json.loads('''{"heading":12}'''),json.loads('''{"heading":120}'''), json.loads('''{"heading":1200}'''),json.loads('''{"heading":false}'''), json.loads('''{"heading":null}''') ]  for input in inputs:     print "%-30s" % json.dumps(input),     try:         validate(input, schema)         print "OK"     except ValidationError as e:         print e.message 

Which gives:

{"heading": 5}                 OK {"heading": 0}                 OK {"heading": 360}               360.0 is greater than or equal to the maximum of 360 {"heading": 360.1}             360.1 is greater than or equal to the maximum of 360 {"heading": -5}                -5.0 is less than the minimum of 0 {"heading": null}              OK {"heading": false}             False is not of type u'number', u'null' {"heading": "X"}               'X' is not of type u'number', u'null' {"heading": 12}                OK {"heading": 120}               OK {"heading": 1200}              1200.0 is greater than or equal to the maximum of 360 {"heading": false}             False is not of type u'number', u'null' {"heading": null}              OK 
like image 45
Adam Matan Avatar answered Sep 28 '22 07:09

Adam Matan