如何在JSON模式中扩展模式?

时间:2018-09-29 08:09:29

标签: json schema jsonschema

我正在使用JSON模式进行数据建模。我定义了一个基本的Document模式,以后可以用来定义模型模式(例如ProductCategoryUser等)。

我这样做是因为我希望所有模型都继承某些结构/规则。例如,每个模型实例都应具有某些公共属性(例如idcreatedAtupdatedAt)。在OOP术语中:Product extends Document,因此它继承其实例属性。在模式术语中(我认为),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
    }
  }
}
  1. 如何指定Document元模式“扩展”基本JSON模式(草案07),这样我就不必定义草稿的所有属性($schema,{{ 1}}等)?
  2. 如何指定每个模型架构的id包含一些公共属性(propertiesid,...),而不必在每个模型架构定义中都定义它们?

2 个答案:

答案 0 :(得分:4)

JSON Schema不使用面向对象的范例,因此继承等概念无法很好地转换。 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。

/ schema / override

{
  "allOf": [{ "$ref": "/schema/base" }],
  "properties": {
    "bar": { "type": "integer" },
    "baz": { "type": "boolean" }
  }
}

在此示例中,两个模式都有一个/properties/bar字段。如果您从继承的角度考虑这一点,那么您会误解这里发生的事情。在这种情况下,两者“ / properties / bar”字段都必须有效。没有冲突可以解决。就像关键字所说,“所有”架构都必须有效。

希望能为您提供足够的信息来解决您的问题并避免最常见的陷阱。

答案 1 :(得分:1)

在使用NodeJ时,使用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)

这至少解决了我的用例。