Validating Heterogeneous Lists of Objects with JsonSchema and $ref

删除回忆录丶 提交于 2019-12-25 02:15:23

问题


I have seen answers to similar questions that do not quite match this particular case, so apologies if I missed a relevant answer.

I have a heterogeneous array of objects that I would like to validate. These objects have the same format at the top level, but the child objects are quite different and can only be identified by the attributes present in each child.

The problem maps to validating the following data, though I have more than two object types in the array:

{
  "heterogeneous_array": [{
      "arbitrary_name": "foobar",
      "params": {
        "aa": "foo",
        "ab": "bar"
      }
    },
    {
      "arbitrary_name": "barfoo",
      "params": {
        "ba": "baz",
        "bb": "bot"
      }
    }
  ]
}

I am using the following schema, which claims to validate the input json even when the objects under the “params” key are invalid. How can I fix the json schema?

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "heterogeneous_array": {
      "$ref": "#/definitions/heterogeneous_array"
    }
  },
  "definitions": {
    "heterogeneous_array": {
      "type": "array",
      "items": {
        "arbitrary_name": {
          "type": "string"
        },
        "params": {
          "oneOf": [{
              "$ref": "#/definitions/schema_a"
            },
            {
              "$ref": "#/definitions/schema_b"
            }
          ]
        },
        "required": ["arbitrary_name", "params"]
      }
    },
    "schema_a": {
      "properties": {
        "aa": {
          "type": "string"
        },
        "ab": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["aa", "ab"]
    },
    "schema_b": {
      "properties": {
        "ba": {
          "type": "string"
        },
        "bb": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["ba", "bb"]
    }
  }
}

Thank you in advance!


回答1:


The first thing that jumps out at me is that parameters and arbitrary_name are not JSON Schema keywords. I think you're missing a few properties keywords.

Try this:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "heterogeneous_array": {
      "$ref": "#/definitions/heterogeneous_array"
    }
  },
  "definitions": {
    "heterogeneous_array": {
      "type": "array",
      "items": {
        "properties": {             // missing this
          "arbitrary_name": {
            "type": "string"
          },
          "params": {
            "oneOf": [{
                "$ref": "#/definitions/schema_a"
              },
              {
                "$ref": "#/definitions/schema_b"
              }
            ]
          }
        },
        "required": ["arbitrary_name", "params"]    // "arbitrary_name" was "name"
      }
    },
    "schema_a": {
      "properties": {             // was "parameters"
        "aa": {
          "type": "string"
        },
        "ab": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["aa", "ab"]
    },
    "schema_b": {
      "properties": {             // was "parameters"
        "ba": {
          "type": "string"
        },
        "bb": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["ba", "bb"]
    }
  }
}

There are a few other things in there that I commented.

The last thing (to fix what you have) is minor, should be noted, and is probably supported by your JSON library anyway: boolean values in JSON are always lower-case (e.g. false not False). (They're actually defined as explicit tokens.)


What is unclear from your question is whether the foobar object requires the aa and ab parameters while the barfoo object requires the ba and bb parameters. If this is the case, you can do some other things if you're using JSON Schema draft 6 or higher.

Draft 6 defines a const property that you can use to isolate values for specific properties and enforce subschemas on other portions of the object. Using this, you can create a sort of switch statement.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "heterogeneous_array": {
      "$ref": "#/definitions/heterogeneous_array"
    }
  },
  "definitions": {
    "heterogeneous_array": {
      "type": "array",
      "items": {
        "oneOf": [
          {"$ref": "#/definitions/schema_a"},
          {"$ref": "#/definitions/schema_b"}
        ],
        "required": ["arbitrary_name", "params"]
      }
    },
    "schema_a": {
      "properties": {
        "arbitrary_name": {"const": "foobar"},
        "params": {
          "properties": {
            "aa": {
              "type": "string"
            },
            "ab": {
              "type": "string"
            }
          },
          "additionalProperties": false,
          "required": ["aa", "ab"]
        }
      }
    },
    "schema_b": {
      "properties": {
        "arbitrary_name": {"const": "barfoo"},
        "params": {
          "properties": {
            "ba": {
              "type": "string"
            },
            "bb": {
              "type": "string"
            }
          },
          "additionalProperties": false,
          "required": ["ba", "bb"]
        }
      }
    }
  }
}

This is a bit of a reorganization and you'll need a schema_? for each value of arbitrary_name that you have.

Further to this, if you're using draft 7, you also have the if/then/else keywords, but I don't think that makes this use case any cleaner.



来源:https://stackoverflow.com/questions/55168214/validating-heterogeneous-lists-of-objects-with-jsonschema-and-ref

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!