根据uri参数有条件地要求jsonSchema属性

时间:2017-07-11 12:28:31

标签: jsonschema

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

  • 此uri参数foo必须包含值fooBarfooBaz之一。否则请求标记为404。
  • 如果foo的值为fooBar,则需要正文属性bar
  • 如果foo的值为fooBaz,则需要正文属性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"]
        },
    ]
}

1 个答案:

答案 0 :(得分:1)

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

在我进入解决方案之前,我想指出一些事情。您的$schema设置为" draft-03"。如果你真的需要" draft-03",这个解决方案不会起作用。在{" draft-04"中添加了anyOfallOf和数组形式的required。在{" draft-06"中添加了hrefSchema。自" draft-06"是全新的,并没有得到很好的支持,无论如何你都不需要hrefSchema,我会假设"选秀04" ("草案05"被有效跳过)。

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

在我进入解决方案之前的最后一件事。如果您使用的是link关键字,那么您使用的是JSON超模式,$schema应该反映出来。它应该有"超模式"而不是"架构"在URI的末尾。

现在的解决方案。我把它分为两部分,你通过验证器发出的模式和告诉用户如何发出请求的超模式。你有第一个正确的。我只修复了$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,我需要重构。我建议花几分钟时间考虑替代设计,因为这不需要对枚举进行切换。