I try to validate JSON in python using jsonschema library. What I want to achieve is a dictionary with keys conststing of json keys causing trouble and messages from validator as values.
There is no problem with type validation as it returns path to json key which does not pass validation. My problem is when key is missing path variable in ValidationError is empty and I can't find any other place where it's stated which json key is causing trouble. The only place that states which json key is the problem is message, but spliting it to extract that information seems more like workaround than solution.
Code:
import jsonschema
schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"email": {
"type": "string"
}
},
"required": ["name", "email"]
}
jsonToValidate = {
"name": 1234
}
validator = jsonschema.Draft202012Validator(schema)
errorsGenerator = validator.iter_errors(jsonToValidate)
errors = dict()
for err in errorsGenerator:
# errors.update({err.path[0], err.message})
print("path: ", err.path, " \n message: ", err.message)
Current output:
path: deque(['name'])
message: 1234 is not of type 'string'
path: deque([])
message: 'email' is a required property
Expected output: Dictionary with key as json key that is troublesome and message as value. For this example it would look like this:
{
"name": "1234 is not of type 'string'",
"email": 'email' is a required property
}
So my question is: Is it possible to extract information which missing json key (that is required by schema) caused ValidationError?
There is an open bug report for exactly your problem in the jsonschema
repo, with the short answer that there is currently no standard way for getting the missing required key. However, a comment to the report mentions a workaround via custom validators. Maybe this would be a way to go for you as well.
Update: Alternatively, you can maybe use a mix of message parsing and using available attributes: Parse the error message for required
keys, as suggested in user2704177's answer; otherwise, use the ValidationError
's path
where possible. So, something like:
errors = dict()
for err in errorsGenerator:
if err.validator == "required":
# Parse first word of error message as key, strip surrounding quotes
errors[err.message.split(" ")[0].strip("'")] = err.message
else:
# Use last path element as key (empty string for empty path)
errors[err.path[-1] if err.path else ""] = err.message
print(errors)
# >>> {'name': "1234 is not of type 'string'", 'email': "'email' is a required property"}