Package: jtd
jtd: JSON Validation for Pythonjtdis a Python implementation ofJSON Type Definition, a schema
language for JSON.jtdprimarily gives you two things:Validating input data against JSON Typedef schemas.A Python representation of JSON Typedef schemas.With this package, you can add JSON Typedef-powered validation to your
application, or you can build your own tooling on top of JSON Type Definition.InstallationYou can install this package withpip:pipinstalljtdDocumentationDetailed API documentation is available online at:https://jtd.readthedocs.ioFor more high-level documentation about JSON Typedef in general, or JSON Typedef
in combination with Python in particular, see:The JSON Typedef Website"Validating JSON in Python with JSON Typedef"Basic UsageFor a more detailed tutorial and guidance on how to integratejtdin your
application, see"Validating JSON in Python with JSON
Typedef"in the JSON Typedef docs.Here's an example of how you can use this package to validate JSON data against
a JSON Typedef schema:importjtdschema=jtd.Schema.from_dict({'properties':{'name':{'type':'string'},'age':{'type':'uint32'},'phones':{'elements':{'type':'string'}}}})# jtd.validate returns an array of validation errors. If there were no problems# with the input, it returns an empty array.# Outputs: []print(jtd.validate(schema=schema,instance={'name':'John Doe','age':43,'phones':['+44 1234567','+44 2345678'],}))# This next input has three problems with it:## 1. It's missing "name", which is a required property.# 2. "age" is a string, but it should be an integer.# 3. "phones[1]" is a number, but it should be a string.## Each of those errors corresponds to one of the errors returned by validate.# Outputs:## [#   ValidationError(#     instance_path=[], schema_path=['properties', 'name']#   ),#   ValidationError(#     instance_path=['age'], schema_path=['properties', 'age', 'type']#   ),#   ValidationError(#     instance_path=['phones', '1'], schema_path=['properties', 'phones', 'elements', 'type']#   ),# ]print(jtd.validate(schema=schema,instance={'age':"43",'phones':["+44 1234567",442345678],}))Advanced Usage: Limiting Errors ReturnedBy default,jtd.validatereturns every error it finds. If you just care about
whether there are any errors at all, or if you can't show more than some number
of errors, then you can get better performance out ofjtd.validateusing themax_errorsoption.For example, taking the same example from before, but limiting it to 1 error, we
get:# Outputs:## [ValidationError(instance_path=[], schema_path=['properties', 'name'])]options=jtd.ValidationOptions(max_errors=1)print(jtd.validate(schema=schema,options=options,instance={'age':'43','phones':['+44 1234567',442345678],}))Advanced Usage: Handling Untrusted SchemasIf you want to runjtdagainst a schema that you don't trust, then you should:Ensure the schema is well-formed, using thevalidate()method onjtd.Schema. That will check things like making sure allrefs have
corresponding definitions.Calljtd.validatewith themax_depthoption. JSON Typedef lets you write
recursive schemas -- if you're evaluating against untrusted schemas, you
might go into an infinite loop when evaluating against a malicious input,
such as this one:{"ref":"loop","definitions":{"loop":{"ref":"loop"}}}Themax_depthoption tellsjtd.validatehow manyrefs to follow
recursively before giving up and throwingjtd.MaxDepthExceededError.Here's an example of how you can usejtdto evaluate data against an untrusted
schema:importjtd# validate_untrusted returns true if `data` satisfies `schema`, and false if it# does not. Throws an error if `schema` is invalid, or if validation goes in an# infinite loop.defvalidate_untrusted(schema,data):schema.validate()# You should tune max_depth to be high enough that most legitimate schemas# evaluate without errors, but low enough that an attacker cannot cause a# denial of service attack.options=jtd.ValidationOptions(max_depth=32)returnlen(jtd.validate(schema=schema,instance=data,options=options))==0}# Returns truevalidate_untrusted(jtd.Schema.from_dict({'type':'string'}),'foo')# Returns falsevalidate_untrusted(jtd.Schema.from_dict({'type':'string'}),None)# Throws "invalid schema"validate_untrusted(jtd.Schema.from_dict({'type':'nonsense'}),'foo')# Throws an instance of jtd.MaxDepthExceededErrorvalidate_untrusted({"ref":"loop","definitions":{"loop":{"ref":"loop"}}},None)