【问题标题】:Conditional References in a JSON SchemaJSON 模式中的条件引用
【发布时间】:2021-07-23 08:07:09
【问题描述】:

我想编写一个包含多个子模式的单个文件 JSON 模式定义,我可以根据负载组合这些子模式。

以下架构验证我的架构正在处理我的示例 JSON 响应。 (响应对象的 payload.role 类型错误,以确保架构捕获此错误!)

为了清楚起见,我在最重要的部分减少了它。可以在此处找到完整的工作示例:https://www.jsonschemavalidator.net/s/3KAaXjtg

架构

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "$id": "http://example.com/baseSchema.json",
  "type": "object",
  "required": [
    "payload"
  ],
  "properties": {
    "payload": {
      "$id": "#/properties/payload",
      "type": "object",
      // reference the right schema depending on the payload child key
      // if `payload.user` reference `userSchema.json`
      // if `payload.users` reference `usersSchema.json`
      // if `payload.*` reference `*Schema.json`
      "$ref": "userSchema.json"
    }
  },
  "definitions": {
    "user": {
      "$id": "http://example.com/userSchema.json",
      "type": "object",
      "required": [
        "user"
      ],
      "properties": {
        "user": {
          "type": "object",
          "$ref": "userProperties.json"
        }
      }
    },
    "users": {
      "$id": "http://example.com/usersSchema.json",
      "type": "object",
      "required": [
        "users"
      ],
      "properties": {
        "users": {
          "type": "array",
          "items": {
            "$ref": "userProperties.json"
          }
        }
      }
    },
    "userProperties": {
      "$id": "http://example.com/userProperties.json",
      "type": "object",
      "properties": {
        "firstName": {
          "$id": "#/properties/payload/properties/user/properties/firstName",
          "type": "string"
        }
      }
    }
  }
}

回应

{
  "status": {
    "code": 200,
    "description": "User retrieved successfully."
  },
  "payload": {
    "user": {
      "firstName": "Joe",
      "lastName": "Doe",
      "role": "3", // for testing reasons, this is the wrong type!
      "email": "doe@example.com",
      "customerID": "",
      "projects": [
        "AIXG5mEg6QLl9rhVSE6m",
        "Bs1bHiOIqKclwwis3CNf",
        "NC2OUGVZXU35FA7iwRn4"
      ],
      "status": "Status",
      "id": "c555BSZnKLdHSRYqrU5hqiQo733j13"
    }
  }
}

所以我有一个与此响应匹配的baseSchema.json

{
  "status": {},
  "payload": {}
}

payload 被某个键(如 payload.user = {}payload.foo = {})扩展,并且根据该键,我想用我的定义之一扩展架构。

以下部分仅适用于密钥user

  "properties": {
    "payload": {
      "$id": "#/properties/payload",
      "type": "object",
      // reference the right schema depending on the payload child key
      // if `payload.user` reference `userSchema.json`
      // if `payload.users` reference `usersSchema.json`
      // if `payload.*` reference `*Schema.json`
      "$ref": "userSchema.json"
    }
  },

我未能设置任何conditions(带有allOfifelse),这将基于payload 键引用正确的子架构。

感谢任何提示和帮助解决这个问题。

【问题讨论】:

  • 条件是否互斥?无论哪种方式,解决方案都是相似的,但是如果不磕头,解决方案可能对您不起作用
  • @Relequestual 他们是独家的。只能引用一个 *Schema.json。解决方法类似于什么?
  • 不管你的回答如何,解决方案(我会提供)都是相似的
  • 啊...跟进问题,您是否提前知道所有可能的密钥?这不能动态完成。
  • 是的,可能的键是已知的。我希望有一个动态的解决方案,但我可以看到这在静态文档的上下文中没有意义。

标签: json jsonschema


【解决方案1】:

最后的架构和演示链接...让我们看看我们是如何到达那里的...

在 JSON Schema Draft-07 及之前的版本中,您不能将 $ref 与其他关键字一起使用。其他关键字被忽略。 (在您的架构http://example.com/userSchema.json 中,您在$ref 旁边有type)。幸运的是,当您在引用的模式中声明类型时,这并没有给您带来任何问题。 (您可以在 2019-09 或更高版本中执行此操作。)

关键字ifthenelse 的值是模式。 要将 then 子架构应用于您的实例位置,if 架构必须返回有效。如果失败,将应用 else 子模式值。

我们的 if 条件检查特定键的存在。 如果密钥存在,则应用引用正确架构的架构。

由于希望条件互斥,需要将多个条件包装在oneOf 中,并将else: false 添加到条件检查中。 false 作为架构使验证失败。

如果您想进一步澄清上述任何内容,请告诉我。

演示:https://jsonschema.dev/s/HLniL

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "$id": "http://example.com/baseSchema.json",
  "type": "object",
  "required": [
    "payload"
  ],
  "properties": {
    "payload": {
      "$id": "#/properties/payload",
      "type": "object",
      "oneOf": [
        {
          "if": {
            "required": [
              "user"
            ]
          },
          "then": {
            "$ref": "userSchema.json"
          },
          "else": false
        },
        {
          "if": {
            "required": [
              "users"
            ]
          },
          "then": {
            "$ref": "usersSchema.json"
          },
          "else": false
        }
      ]
    }
  },
  "definitions": {
    "user": {
      "$id": "http://example.com/userSchema.json",
      "type": "object",
      "required": [
        "user"
      ],
      "properties": {
        "user": {
          "$ref": "userProperties.json"
        }
      }
    },
    "users": {
      "$id": "http://example.com/usersSchema.json",
      "type": "object",
      "required": [
        "users"
      ],
      "properties": {
        "users": {
          "type": "array",
          "items": {
            "$ref": "userProperties.json"
          }
        }
      }
    },
    "userProperties": {
      "$id": "http://example.com/userProperties.json",
      "type": "object",
      "properties": {
        "firstName": {
          "type": "string"
        }
      }
    }
  }
}

【讨论】:

  • 非常感谢您的示例和解释。这更有意义,现在我用自己的数据看到了条件:)。我不明白的是:在您的示例和我的示例 (jsonschemavalidator.net/s/366lU11Y) 中,我正在寻找的类型错误与条件错误一起列出。这些可以忽略吗?还是有更好的方法来解决我的问题?
  • 不客气!不幸的是,无法确定您正在尝试执行有效切换逻辑的操作。其他类似的规范可能称其为“鉴别器”,但 JSON Schema 中不存在这样的东西。如果您的架构是这样编写的,因此这些条件是互斥的,您应该能够解析错误以确定满足哪个条件,但架构的内容失败,因为错误路径将包括 then 而不是 else。我们希望有标准化的错误格式,人们可能会为这种情况制作独立的工具! ?
  • 所以我想我的选择是写出所有内容,和/或使用 JavaScript 动态合并模式(我正在尝试在 Postman 中使用它;-))。
  • 您可以使用 Jasonnet 之类的工具将您的模式动态元素构建到静态文档中,然后使用 Postman 中的 Postman API 创建或更新您的集合(或其他)。
  • 使用dependencies 关键字jsonschemavalidator.net/s/JHEmWdby,您将获得更好的错误消息传递
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多