Interpretation of JSON Schema to CommonModel
The library transforms JSON Schema from data validation rules to data definitions (CommonModel
(s)).
The algorithm tries to get to a model whose data can be validated against the JSON schema document.
As of now we only provide the underlying structure of the schema file for the model, where constraints/annotations such as maxItems
, uniqueItems
, multipleOf
, etc. are not interpreted.
Patterns
Beside the regular interpreter we also look for certain patterns that are interpreted slightly differently.
oneOf
with allOf
If both oneOf and allOf is present, each allOf model is merged into the interpreted oneOf.
For example take this example:
1{ 2 "allOf":[ 3 { 4 "title":"Animal", 5 "type":"object", 6 "properties":{ 7 "animalType":{ 8 "title":"Animal Type", 9 "type":"string" 10 }, 11 "age":{ 12 "type":"integer", 13 "min":0 14 } 15 } 16 } 17 ], 18 "oneOf":[ 19 { 20 "title":"Cat", 21 "type":"object", 22 "properties":{ 23 "animalType":{ 24 "const":"Cat" 25 }, 26 "huntingSkill":{ 27 "title":"Hunting Skill", 28 "type":"string", 29 "enum":[ 30 "clueless", 31 "lazy" 32 ] 33 } 34 } 35 }, 36 { 37 "title":"Dog", 38 "type":"object", 39 "additionalProperties":false, 40 "properties":{ 41 "animalType":{ 42 "const":"Dog" 43 }, 44 "breed":{ 45 "title":"Dog Breed", 46 "type":"string", 47 "enum":[ 48 "bulldog", 49 "bichons frise" 50 ] 51 } 52 } 53 } 54 ] 55}
Here animal is merged into cat and dog.
oneOf
with properties
If both oneOf and properties are both present, it's interpreted exactly like oneOf with allOf. That means that the following:
1{ 2 "title":"Animal", 3 "type":"object", 4 "properties":{ 5 "animalType":{ 6 "title":"Animal Type", 7 "type":"string" 8 }, 9 "age":{ 10 "type":"integer", 11 "min":0 12 } 13 }, 14 "oneOf":[ 15 { 16 "title":"Cat", 17 "type":"object", 18 "properties":{ 19 "animalType":{ 20 "const":"Cat" 21 }, 22 "huntingSkill":{ 23 "title":"Hunting Skill", 24 "type":"string", 25 "enum":[ 26 "clueless", 27 "lazy" 28 ] 29 } 30 } 31 }, 32 { 33 "title":"Dog", 34 "type":"object", 35 "additionalProperties":false, 36 "properties":{ 37 "animalType":{ 38 "const":"Dog" 39 }, 40 "breed":{ 41 "title":"Dog Breed", 42 "type":"string", 43 "enum":[ 44 "bulldog", 45 "bichons frise" 46 ] 47 } 48 } 49 } 50 ] 51}
where all the defined behavior on the root object are merged into the two oneOf models cat and dog.
Interpreter
The main functionality is located in the Interpreter
class. This class ensures to recursively create (or retrieve from a cache) a CommonModel
representation of a Schema. We have tried to keep the functionality split out into separate functions to reduce complexity and ensure it is easy to maintain.
The order of interpretation:
true
boolean schema infers all model types (object
,string
,number
,array
,boolean
,null
,integer
) schemas.type
infers the initial model type.required
are interpreted as is.patternProperties
are merged together with any additionalProperties, where duplicate pattern models are merged.additionalProperties
are interpreted as is, where duplicate additionalProperties for the model are merged. If the schema does not defineadditionalProperties
it defaults totrue
schema.additionalItems
are interpreted as is, where duplicate additionalItems for the model are merged. If the schema does not defineadditionalItems
it defaults totrue
schema.items
are interpreted as ether tuples or simple array, where more than 1 item are merged. Usage ofitems
infersarray
model type.properties
are interpreted as is, where duplicateproperties
for the model are merged. Usage ofproperties
infersobject
model type.- allOf
dependencies
only apply to schema dependencies, since property dependencies adds nothing to the underlying model. Any schema dependencies are interpreted and then merged together with the current interpreted model.enum
is interpreted as is, where eachenum
. Usage ofenum
infers the enumerator value type to the model, but only if the schema does not havetype
specified.const
interpretation overwrite already interpretedenum
. Usage ofconst
infers the constant value type to the model, but only if the schema does not havetype
specified.- allOf/oneOf/anyOf/then/else
- not
Interpreting not schemas
not
schemas infer the form for which the model should not take by recursively interpret the not
schema. It removes certain model properties when encountered.
Currently, the following not
model properties are interpreted:
type
enum
Restrictions
- You cannot use nested
not
schemas to infer new model properties, it can only be used to re-allow them. - boolean
not
schemas are not applied.
Processing sub schemas
The following JSON Schema keywords are merged with the already interpreted model:
allOf
oneOf
anyOf
then
else
Merging models
Because of the recursive nature of the interpreter (and the nested nature of JSON Schema) it happens that two models needs to be merged together.
If only one side has a property defined, it is used as is, if both have it defined they are merged based on the following logic (look here for more information about the CommonModel and its properties):
additionalProperties
if both models contain it the two are recursively merged together.patternProperties
if both models contain it each pattern model are recursively merged together.properties
if both models contain the same property the corresponding models are recursively merged together.items
are merged together based on a couple of rules:- If both models are simple arrays those item models are merged together as is.
- If both models are tuple arrays each tuple model (at specific index) is merged together.
- If either one side is different from the other, the tuple schemas is prioritized as it is more restrictive.
types
if both models contain types they are merged together, duplicate types are removed.enum
if both models contain enums they are merged together, duplicate enums are removed.required
if both models contain required properties they are merged together, duplicate required properties are removed.$id
,$ref
,extend
uses left model value if present otherwise right model value if present.originalSchema
are overwritten.