JSON schema validation, If there are additional keys they have to be of a specified name and type

Question:

I’m a beginner to json (I do not have a history with JS) and only recently I’ve met with the need for json schema and it’s validation. The problem could be described as:
I have 5 keys (properties) in my json; A, B, C, D, E, of which A, B and C are required, but D and E are not, specifically, every combination of D, E and their abscence is valid. However, there cannot be any additional keys other than D and E. Here’s a couple examples (Items in sets represent keys of the object):

{A, B, C, D, E}  # valid
{A, B, C, D}     # valid
{A, B, C, E}     # valid
{A, B, C}        # valid

{A, B, D, E}     # invalid (C key is missing)
{A, B, C, D, Z}  # invalid (Z is not an allowed additional key)
{A, B, C, Z}     # invalid 

First, I’ve tried writing my own validation function, which worked, but in our project we already use jsonschema.validate in other places and my supervisor told me to try solving this problem with the aforementioned method.
Here’s the schema that was closed to solving the problem;

my_schema = {
    "type": "object",
    "maxProperties": 5,
    "required": [
        "A", "B", "C"
    ],
    "properties": {
        "A": {"type": ["boolean", "number"]},
        "B": {"type": "array"},
        "C": {"type": "number"},
        "D": {"type": "string"},
        "E": {"type": "string"}
    }
}

however a test case where the keys are:

{A, B, C, D, Z}

is passing as a valid schema whereas it should not.

Asked By: KrzysiekDD

||

Answers:

Instead of "maxProperties": 5 you could use "additionalProperties": False

Here in code:

import json
from jsonschema import Draft7Validator

my_schema = {
    "type": "object",
    "additionalProperties": False,
    "required": [
        "A", "B", "C"
    ],
    "properties": {
        "A": {"type": ["boolean", "number"]},
        "B": {"type": "array"},
        "C": {"type": "number"},
        "D": {"type": "string"},
        "E": {"type": "string"}
    }
}

data = {
    "A": True,
    "B": [1, 2, 3],
    "C": 1,
    "D": "test",
    "E": "test"
}

validator = Draft7Validator(my_schema)
validator.validate(data)

The above will validate fine, while the below will fail:

bad_data = {
    "A": True,
    "B": [1, 2, 3],
    "C": 1,
    "D": "test",
    "Z": "test"
}

validator.validate(bad_data)

It will give you this error:

---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
/Users/danielsc/git/bwinf/41/Junior2/test.ipynb Cell 70 in <cell line: 10>()
      1 bad_data = {
      2     "A": True,
      3     "B": [1, 2, 3],
   (...)
      6     "Z": "test"
      7 }
      9 validator = Draft7Validator(my_schema)
---> 10 validator.validate(bad_data)

File /usr/local/Caskroom/miniconda/base/envs/hugging/lib/python3.10/site-packages/jsonschema/validators.py:269, in create.<locals>.Validator.validate(self, *args, **kwargs)
    267 def validate(self, *args, **kwargs):
    268     for error in self.iter_errors(*args, **kwargs):
--> 269         raise error

ValidationError: Additional properties are not allowed ('Z' was unexpected)

Failed validating 'additionalProperties' in schema:
    {'additionalProperties': False,
     'properties': {'A': {'type': ['boolean', 'number']},
                    'B': {'type': 'array'},
                    'C': {'type': 'number'},
                    'D': {'type': 'string'},
                    'E': {'type': 'string'}},
     'required': ['A', 'B', 'C'],
     'type': 'object'}

On instance:
    {'A': True, 'B': [1, 2, 3], 'C': 1, 'D': 'test', 'Z': 'test'}
Answered By: Daniel Schneider