Piotr Olaszewski
Piotr Olaszewski

Reputation: 6204

JsonSchema polymorphic object depends on other field

I have following JSONs:

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

And I would like to validate:

I figure something like:

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

But this not valid well when e.g.: type is message and payload has url.

Upvotes: 1

Views: 282

Answers (2)

Jason Desrosiers
Jason Desrosiers

Reputation: 24439

Using oneOf for this type of thing is terrible for error messaging. Here's an alternative using if/then that's more verbose, but is better for error messaging and performance.

{
  "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"] }
        }
      }
    }
  ]
}

Upvotes: 2

Ethan
Ethan

Reputation: 725

you should move the oneOf up to describe the whole message/image/video object, and replace the enum for the "type" property with individual const values across the oneOf schemas:

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

Upvotes: 3

Related Questions