如何在 JSON 架构中扩展架构?
How to extend a schema in JSON schema?
我正在使用 JSON 模式进行数据建模。我定义了一个基础 Document
模式,稍后我用它来定义模型模式(例如 Product
、Category
、User
等)。
我这样做是因为我希望所有模型都继承某些 structure/rules。例如,每个模型实例都应具有某些公共属性(例如,id
、createdAt
、updatedAt
)。在 OOP 术语中:Product extends Document
因此它继承了它的实例属性。在模式术语中(我认为)Document
是用于创建模型模式的元模式。
我已将文档架构定义如下:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://example.com/schemas/document.json#",
"title": "Document",
"type": "object",
"additionalProperties": false,
"required": ["type", "name", "fields"],
"properties": {
"type": {
"constant": "document"
},
"name": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"readOnly": {
"type": "boolean"
},
"properties": {
// common properties
// model-specific properties
}
}
}
- 如何指定文档元模式 "extends" 基本 JSON 模式 (draft-07),这样我就不必定义草稿的所有属性 (
$schema
、id
等)?
- 如何指定每个模型架构的
properties
包含一些公共属性(id
、createdAt
、...),而不必在每个模型中定义它们架构定义?
JSON 架构不使用面向对象的范例,因此继承等概念不能很好地翻译。 JSON 架构是约束的集合。它是减法而不是像大多数人习惯的那样加法。这意味着给定一个空模式,valid JSON 文档集是 all JSON 文档集。添加关键字时,您正在从有效 JSON 文档集中减去。一旦从集合中删除某些内容,就无法将其添加回去。
因此,您可以使用组合来“扩展”模式,但永远不能“覆盖”另一个模式定义的内容。
让我们看一个没有冲突属性的简单扩展示例。
/schema/base
{
"type": "object",
"properties": {
"foo": { "type": "string" },
"bar": { "type": "string" }
}
}
/schema/extended
{
"allOf": [{ "$ref": "/schema/base" }],
"properties": {
"baz": { "type": "string" }
}
}
这与 JSON 架构配合得很好。现在让我们看一个 属性 定义冲突的例子。
/schema/override
{
"allOf": [{ "$ref": "/schema/base" }],
"properties": {
"bar": { "type": "integer" },
"baz": { "type": "boolean" }
}
}
在此示例中,两个模式都有一个 /properties/bar
字段。如果您从继承的角度考虑这一点,您就会误解这里发生的事情。在这种情况下,both“/properties/bar”字段必须有效。没有冲突需要解决。正如关键字所说,“所有”模式必须有效。由于 bar
不可能既是整数又是字符串,因此没有文档会根据 /schema/override
.
进行验证
希望这能为您提供足够的信息来解决您的问题并避免最常见的问题。
使用 NodeJs 时,使用 ajv 验证器可以直接绕过简单模式的这一限制,如下所示:
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)
这至少解决了我的用例。
我正在使用 JSON 模式进行数据建模。我定义了一个基础 Document
模式,稍后我用它来定义模型模式(例如 Product
、Category
、User
等)。
我这样做是因为我希望所有模型都继承某些 structure/rules。例如,每个模型实例都应具有某些公共属性(例如,id
、createdAt
、updatedAt
)。在 OOP 术语中:Product extends Document
因此它继承了它的实例属性。在模式术语中(我认为)Document
是用于创建模型模式的元模式。
我已将文档架构定义如下:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "http://example.com/schemas/document.json#",
"title": "Document",
"type": "object",
"additionalProperties": false,
"required": ["type", "name", "fields"],
"properties": {
"type": {
"constant": "document"
},
"name": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"readOnly": {
"type": "boolean"
},
"properties": {
// common properties
// model-specific properties
}
}
}
- 如何指定文档元模式 "extends" 基本 JSON 模式 (draft-07),这样我就不必定义草稿的所有属性 (
$schema
、id
等)? - 如何指定每个模型架构的
properties
包含一些公共属性(id
、createdAt
、...),而不必在每个模型中定义它们架构定义?
JSON 架构不使用面向对象的范例,因此继承等概念不能很好地翻译。 JSON 架构是约束的集合。它是减法而不是像大多数人习惯的那样加法。这意味着给定一个空模式,valid JSON 文档集是 all JSON 文档集。添加关键字时,您正在从有效 JSON 文档集中减去。一旦从集合中删除某些内容,就无法将其添加回去。
因此,您可以使用组合来“扩展”模式,但永远不能“覆盖”另一个模式定义的内容。
让我们看一个没有冲突属性的简单扩展示例。
/schema/base
{
"type": "object",
"properties": {
"foo": { "type": "string" },
"bar": { "type": "string" }
}
}
/schema/extended
{
"allOf": [{ "$ref": "/schema/base" }],
"properties": {
"baz": { "type": "string" }
}
}
这与 JSON 架构配合得很好。现在让我们看一个 属性 定义冲突的例子。
/schema/override
{
"allOf": [{ "$ref": "/schema/base" }],
"properties": {
"bar": { "type": "integer" },
"baz": { "type": "boolean" }
}
}
在此示例中,两个模式都有一个 /properties/bar
字段。如果您从继承的角度考虑这一点,您就会误解这里发生的事情。在这种情况下,both“/properties/bar”字段必须有效。没有冲突需要解决。正如关键字所说,“所有”模式必须有效。由于 bar
不可能既是整数又是字符串,因此没有文档会根据 /schema/override
.
希望这能为您提供足够的信息来解决您的问题并避免最常见的问题。
使用 NodeJs 时,使用 ajv 验证器可以直接绕过简单模式的这一限制,如下所示:
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)
这至少解决了我的用例。