How to extend a schema in JSON schema?
When using NodeJs, it is straightforward to get around this limitation on simple schemas with a little code using ajv validator like this:
function extendJsonSchema(baseSchema, extendingSchema) {
let extendedSchema = Object.assign({}, extendingSchema);
extendedSchema.properties = Object.assign(extendedSchema.properties, baseSchema.properties)
extendedSchema.required = extendedSchema.required.concat(baseSchema.required)
return extendedSchema
}
let baseSchema = require('./base.schema.json')
let extendingSchema = require('./extending.schema.json')
let extendedSchema = extendJsonSchema(baseSchema, extendingSchema)
const validate = ajv.compile(extendedSchema)
This solves my use-case at least.
JSON Schema doesn't use an object oriented paradigm, so concepts like inheritance don't translate well. JSON Schema is a collection of constraints. It's subtractive rather than additive like most people are used to. This means that given an empty schema, the set of valid JSON documents is the set of all JSON documents. As you add keywords, you are subtracting from the set of valid JSON documents. Once something is removed from the set, it can't be added back in.
Therefore, you can use composition to "extend" a schema, but you can never "override" something that another schema defines.
Let's look at a simple extension example with no conflicting properties.
/schema/base
{
"type": "object",
"properties": {
"foo": { "type": "string" },
"bar": { "type": "string" }
}
}
/schema/extended
{
"allOf": [{ "$ref": "/schema/base" }],
"properties": {
"baz": { "type": "string" }
}
}
That works great with JSON Schema. Now let's look at an example with conflicting property definitions.
/schema/override
{
"allOf": [{ "$ref": "/schema/base" }],
"properties": {
"bar": { "type": "integer" },
"baz": { "type": "boolean" }
}
}
In this example, both schemas have a /properties/bar
field. If you are thinking about this in terms of inheritance, you're going to misunderstand what is happening here. In this case, both "/properties/bar" fields must be valid. There is no conflict to resolve. As the keyword says, "all of" the schemas must be valid. Since bar
can't possibly be both an integer and a string, no document will ever validate against the /schema/override
.
Hopefully that gives you enough information to solve your problem and avoid the most common gotcha.