JsonSchema 多态对象依赖其他字段

JsonSchema polymorphic object depends on other field

我有以下 JSON:

[
  {
    "type": "message",
    "payload": {
      "message": "some message"
    }
  },
  {
    "type": "image",
    "payload": {
      "url": "http://example.com/foo/bar"
    }
  },
  {
    "type": "video",
    "payload": {
      "url": "http://example.com/foo/baz"
    }
  }
]

我想验证:

我想是这样的:

{
  "type": "object",
  "properties": {
    "type": {
      "enum": ["message", "image", "video"]
    },
    "payload": {
      "type": "object",
      "oneOf": [
        {
          "properties": {
            "message": {
              "type": "string"
            }
          },
          "required": ["message"]
        },
        {
          "properties": {
            "url": {
              "type": "string"
            }
          },
          "required": ["url"]
        }
      ]
    }
  }
}

但是当 typemessage 并且 payloadurl.

时,这不太有效

您应该将 oneOf 向上移动以描述整个 message/image/video 对象,并将“类型”属性 的 enum 替换为单个 const oneOf 模式中的值:

{
  "type": "object",
  "oneOf": [
    {
      "properties": {
        "type": {
          "const": "message",
        },
        "payload": {
          (message payload schema)
        }
      }
    },
    {
      "properties": {
        "type": {
          "const": "image",
        },
        "payload": {
          (image payload schema)
        }
      },
    }
  ]
}

对这种类型的事情使用 oneOf 对于错误消息来说是很糟糕的。这是使用 if/then 的替代方法,它更冗长,但更适合错误消息和性能。

{
  "type": "object",
  "properties": {
    "type": { "enum": ["message", "image", "video"] },
    "payload": {
      "message": { "type": "string" },
      "url": { "type": "string", "format": "uri" }
    }
  },

  "allOf": [
    {
      "if": {
        "properties": {
          "type": { "const": "message" }
        },
        "required": ["type"]
      },
      "then": {
        "properties": {
          "payload": { "required": ["message"] }
        }
      }
    },
    {
      "if": {
        "properties": {
          "type": { "enum": ["image", "video"] }
        },
        "required": ["type"]
      },
      "then": {
        "properties": {
          "payload": { "required": ["url"] }
        }
      }
    }
  ]
}