【问题标题】:jsonSchema attribute conditionally required based on uri parameter根据 uri 参数有条件地需要 jsonSchema 属性
【发布时间】:2017-07-11 12:28:30
【问题描述】:

考虑一个带有端点的 API,您可以在其中将参数 foo 作为 URL 路径的一部分传递,并在 POST 请求的正文中将一些参数作为 json 传递。

  • 此 uri 参数foo 必须具有值fooBarfooBaz 之一。否则,请求会生成 404。
  • 如果foo 的值为fooBar,则需要body 属性bar
  • 如果foo 的值为fooBaz,则需要body 属性baz

如何为这样的端点指定 jsonSchema?


此类请求的示例是:

POST /path/to/endpoint/fooBar HTTP/1.1
Accept: application/json
Content-Type: application/json
Content-Length: 20
{"bar":"something"}

到目前为止,我根据thisthat 提出了以下内容,但我不知道这是否正确。

{
    "$schema": "http://json-schema.org/draft-03/schema#",
    "id": "http://json-schema.org/draft-03/schema#",
    "definitions": {
        "foo": { "enum": ["fooBar", "fooBaz"] }
    },
    "type": "object",
    "properties": {
        "foo": { "$ref": "#/definitions/foo" },
        "bar": { "type": "string" },
        "baz": { "type": "string" }
    },
    "links": [{
        "rel": "self",
        "href": "/path/to/endpoint/{foo}",
        "hrefSchema": {
            "properties": {
                "foo": {"$ref": "#/definitions/foo"}
            }
        }
    }],
    "anyOf": [
        {
            "properties": {
                "foo": { "enum": ["fooBar"] }
            },
            "required": ["bar"]
        },
        {
            "properties": {
                "foo": { "enum": ["fooBaz"] }
            },
            "required": ["baz"]
        },
    ]
}

【问题讨论】:

    标签: jsonschema


    【解决方案1】:

    JSON 模式验证不知道被验证数据来自的 URI(如果有)。您可以使用 JSON Hyper-Schema 告诉您的用户如何以您期望的方式发送该数据,但您仍需要在服务器端进行额外检查以验证请求是否正确发送。

    在讨论解决方案之前,我想指出几点。您的$schema 设置为“draft-03”。如果您确实需要“draft-03”,则此解决方案将不起作用。在“draft-04”中增加了anyOfallOfrequired的数组形式。 hrefSchema 已添加到“draft-06”中。由于“draft-06”是全新的,还没有得到很好的支持,而且你不需要hrefSchema,我将假设“draft-04”(“draft-05”被有效地跳过)。

    接下来要提到的是你使用了id 错误。它应该是 your 架构的标识符。您通常不需要它,但如果您需要,它应该是标识您的架构的完整 URI。这就是我的解决方案使用它的方式。

    在我进入解决方案之前的最后一件事。如果您使用的是 link 关键字,那么您使用的是 JSON Hyper-Schema 并且您的 $schema 应该反映这一点。它应该在 URI 的末尾有“hyper-schema”而不是“schema”。

    现在解决方案。我把它分成两部分,你通过验证器的模式和告诉用户如何提出请求的超模式。你第一个是对的。我只修复了$schemaid

    {
      "$schema": "http://json-schema.org/draft-04/schema#",
      "id": "http://example.com/schema/my-foo-schema",
      "type": "object",
      "properties": {
        "foo": { "enum": ["fooBar", "fooBaz"] },
        "bar": { "type": "string" },
        "baz": { "type": "string" }
      },
      "anyOf": [
        {
          "properties": {
            "foo": { "enum": ["fooBar"] }
          },
          "required": ["bar"]
        },
        {
          "properties": {
            "foo": { "enum": ["fooBaz"] }
          },
          "required": ["baz"]
        }
      ]
    }
    

    接下来是超模式。您不能在请求架构中引用任何外部(href、实例数据),但您可以编写架构以使其与您的href 匹配。重复是不幸的,但这是你必须这样做的方式。

    {
      "$schema": "http://json-schema.org/draft-04/hyper-schema#",
      "links": [
        {
          "rel": "http://example.com/rel/my-foo-relation",
          "href": "/path/to/endpoint/fooBar",
          "method": "POST",
          "schema": {
            "allOf": [{ "$ref": "http://example.com/schema/my-foo-schema" }],
            "properties": {
              "foo": { "enum": ["fooBar"] }
            }
          }
        },
        {
          "rel": "http://example.com/rel/my-foo-relation",
          "href": "/path/to/endpoint/fooBaz",
          "method": "POST",
          "schema": {
            "allOf": [{ "$ref": "http://example.com/schema/my-foo-schema" }],
            "properties": {
              "foo": { "enum": ["fooBaz"] }
            }
          }
        },
        {
          "rel": "self",
          "href": "/path/to/endpoint"
        }
      ]
    }
    

    通常当我遇到难以用超模式建模的东西时,这意味着我正在使用我的 API 做一些过于复杂的事情,我需要重构。我建议花几分钟时间考虑一下不需要打开枚举的替代设计。

    【讨论】:

      猜你喜欢
      • 2016-12-07
      • 1970-01-01
      • 1970-01-01
      • 2018-03-20
      • 2021-01-25
      • 2018-12-14
      • 2021-07-15
      • 1970-01-01
      相关资源
      最近更新 更多