针对包含多个架构定义的 JSON 架构进行验证

Pix*_*lex 3 json jsonschema postman

我正在创建一个用于 Postman 的 JSON 架构,其中包含一些架构定义。我根据架构验证的 JSON 需要与架构定义之一匹配。

示例模式

{
  "oneOf": [
    {
      "$ref": "#/definitions/schema1"
    },
    {
      "$ref": "#/definitions/schema2"
    },
    {
      "$ref": "#/definitions/schema3"
    }
  ],
  "definitions": {
    "schema1": {
      "type": "object",
      "properties": {
        "propertyA": {
          "type": "string"
        }
      },
      "required": [
        "propertyA"
      ]
    },
    "schema2": {
      "type": "object",
      "properties": {
        "propertyB": {
          "type": "string"
        }
      },
      "required": [
        "propertyB"
      ]
    },
    "schema3": {
      "type": "object",
      "properties": {
        "propertyC": {
          "type": "string"
        }
      },
      "required": [
        "propertyC"
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

示例 JSON 数据

此 JSON 根据架构进行验证并正确标记为无效(因为需要字符串):

{
    "propertyA": 123
}
Run Code Online (Sandbox Code Playgroud)

问题

根据https://www.jsonschemavalidator.net/ ,此示例返回 4 个错误:

  • 消息:JSON 对于“oneOf”中的任何模式均无效。架构路径:#/oneOf
  • 消息:类型无效。预期是字符串,但得到的是整数。架构路径:#/definitions/schema1/properties/propertyA/type
  • 消息:对象:propertyC 中缺少必需的属性。
    架构路径:#/definitions/schema3/required
  • 消息:对象:propertyB 中缺少必需的属性。
    架构路径:#/definitions/schema2/required

我只对错误消息感兴趣,指出它需要一个字符串。如何在将架构定义保留在 1 个单个文件中的同时避免这些其他错误消息?

Jas*_*ers 6

是的,oneOf对于这种事情来说太可怕了。if/then很冗长,但会给你更好的结果。基本上,您需要确定一些条件来确定架构是否应应用于实例。

通常,该条件是公共字段的值。在这种情况下,如果正在验证的实例是一个对象,"type": "A"那么它必须根据/definitions/a模式进行验证。如果有"type": "B",那么它必须根据/definitions/b模式进行验证。

{
  "allOf": [
    {
      "if": {
        "properties": {
          "type": { "const": "A" }
        },
        "required": ["type"]
      },
      "then": { "$ref": "#/definitions/a" }
    },
    {
      "if": {
        "properties": {
          "type": { "const": "B" }
        },
        "required": ["type"]
      },
      "then": { "$ref": "#/definitions/b" }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

如果您的条件是存在特定字段,则可以使用dependencies关键字作为快捷方式。如果正在验证的实例是具有“propertyA”属性的对象,则该实例必须针对架构有效/definitions/a。对于“propertyB”也是如此。

{
  "dependencies": {
    "propertyA": { "$ref": "#/definitions/a" },
    "propertyB": { "$ref": "#/definitions/b" }
  }
}
Run Code Online (Sandbox Code Playgroud)

对于您的示例,实际上有一个超级简单的解决方案,但我回答了一般情况,因为我假设您的实际模式比示例更复杂。

{
  "type": "object",
  "properties": {
    "propertyA": { "type": "string" },
    "propertyB": { "type": "string" },
    "propertyC": { "type": "string" }
  },
  "oneOf": [
    { "required": ["propertyA"] },
    { "required": ["propertyB"] },
    { "required": ["propertyC"] }
  ]
}
Run Code Online (Sandbox Code Playgroud)