是否可以组合部分 JSONSchema 来简化模式定义?

问题描述 投票:0回答:1

我正在构建一个架构,其中有一个要添加的项目数组。每个项目代表一个包含数据和附加的一些元数据(配置值)的实体。

每个实体的元数据几乎总是相同的,因此我的计划是将元数据作为架构中的公共顶级对象。然后在实体列表中,我将拥有实际数据本身的架构。

偶尔,添加一个覆盖是有用的,实体可以从元数据中重新定义特定于其自身的值。这意味着我必须基本上复制每个实体中的元数据模式。

但是,在该重复中,唯一会改变的是

required
ness(基础中所需的属性不需要在覆盖中需要,因为它们已经在基础中需要)。

这是我正在实施的设置示例:

{
  "type": "object",
  "properties": {
    "metadata": {
      "title": "Base metadata values",
      "description": "The base values which most of the array of entities will use (you only want to fill them in once).",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "height": {
          "type": "number"
        }
      },
      "required": [
        "name",
        "height"
      ]
    },
    "entities": {
      "title": "Array of entities",
      "type": "array",
      "items": {
        "title": "An entity",
        "type": "object",
        "properties": {
          "data": {
            "type": "string",
            "description": "actual data associated with each entity"
          },
          "metadata_overrides": {
            "title": "Override base metadata values",
            "description": "Most entities will use the common base values, but each entity could override one or more values. So this object needs to have the same schema as the met, EXCEPT that required fields are no longer required. Is it possible to take the baseField definition then compose it with a different \"required\" property, to avoid duplicating that part of the schema??.",
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "height": {
                "type": "number"
              }
            },
            "required": []
          }
        }
      }
    }
  }
}

如果

properties.metadata
properties.entities.items.properties.metadata_overrides
之间的唯一区别是
required
的值,是否可以将该子模式提取到定义中,然后以某种方式组合它,以便我可以使用定义而不是重复子模式到处都是?

受到这个答案的启发我尝试了这个:

{
  "type": "object",
  "properties": {
    "metadata": {
      "$ref": "#/definitions/metadata"
    },
    "entities": {
      "title": "Array of entities",
      "type": "array",
      "items": {
        "title": "An entity",
        "type": "object",
        "properties": {
          "data": {
            "type": "string",
            "description": "actual data associated with each entity"
          },
          "metadata_overrides": {
            "allOf": [
              {
                "$ref": "#/definitions/metadata"
              }
            ],
            "description": "This description *does* successfully override but the `required` property below doesn't",
            "required": []
          }
        }
      }
    }
  },
  "definitions": {
    "metadata": {
      "title": "Metadata values",
      "description": "Values which most of the array of entities will use (you only want to fill them in once).",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "height": {
          "type": "number"
        }
      },
      "required": [
        "name",
        "height"
      ]
    }
  }
}

但这会对以下数据产生验证错误,该错误应该通过:

{
  "entities": [
    {
      "metadata_overrides": {
        "name": "Dodger"
      }
    }
  ],
  "metadata": {
    "name": "Artful",
    "height": 10
  }
}
jsonschema composition
1个回答
0
投票

是的,您可以通过引用外部模式来组合模式,也可以在同一模式中使用

$defs
。 JSON Schema 具有三个可用的组合关键字:
oneOf
allOf
anyOf

在此处了解更多信息:https://json-schema.org/understanding-json-schema/reference/combining.html#schema-composition

这会验证上面的实例,其中覆盖仅允许

name
height
(互斥),但不能同时允许两者。需求是在架构位置设置的,而不是定义

这是您要找的吗?

{
    "$id": "metadata",
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
        "metadata": {
            "$ref": "#/$defs/metadata",
            "required": [
                "name",
                "height"
            ]
        },
        "entities": {
            "title": "Array of entities",
            "type": "array",
            "items": {
                "title": "An entity",
                "type": "object",
                "properties": {
                    "data": {
                        "type": "string",
                        "description": "actual data associated with each entity"
                    },
                    "metadata_overrides": {
                        "$ref": "#/$defs/metadata",
                        "not": {
                            "required": [
                                "name",
                                "height"
                            ]
                        }
                    }
                }
            }
        }
    },
    "$defs": {
        "metadata": {
            "title": "Base metadata values",
            "description": "The base values which most of the array of entities will use (you only want to fill them in once).",
            "type": "object",
            "properties": {
                "name": {
                    "type": "string"
                },
                "height": {
                    "type": "number"
                }
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.