简体   繁体   中英

JSON Schema: validating an array of custom $ref'd objects

Background: Hi! I've been trying to work on a schema that validates that an array inside an object contains only some of the objects that have been defined inside my definitions block.

As an example, I have the following JSON data to be validated:

{
   "component_type":"section",
   "component_properties":{
      "section_name":"first_section",
      "fields":[
         {
            "component_type":"spacer",
            "component_properties":{
               "width":6
            }
         },
         {
            "component_type":"textbox",
            "component_properties":{
               "display_text":"hello!",
               "text_color":"black"
            }
         },
         {
            "component_type":"spacer",
            "component_properties":{
               "width":3
            }
         }
      ]
   }
}

The idea behind this data is that there is a section "component" defined at the highest level, populated with sub-components that are defined to be validated as well ( spacer , textbox ).

My primary issue: I can't quite figure out how to validate arrays made up exclusively of a few defined objects. My current schema is as follows:

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "type": "object",
  "properties": {
    "component_type": {
      "type": "string",
      "const": "section"
    },
    "component_properties": {
      "type": "object",
      "properties": {
        "section_name": { "type": "string"},
        "sections": {
          "type": "array",
          "oneOf": [
            { "$ref": "#/definitions/section_field" },
            { 
              "type": "array",
              "items": {
                "$ref": "#/definitions/section_field"
              }
            }
          ]
        }
      }
    }
  },
  "definitions": {
    "spacer": {
      "type": "object",
      "properties": {
        "component_type": {
          "type": "string",
          "const": "spacer"
        },
        "component_properties": {
          "width": "number"
        }
      }
    },
    "textbox": {
      "type": "object",
      "properties": {
        "component_type": {
          "type": "string",
          "const": "textbox"
        },
        "component_properties": {
          "display_text": "hello!",
          "text_color": "purple"
        }
      }
    },
    "section_field": {
      "oneOf": [
        {
          "$ref": "#/definitions/spacer"
        },
        {
          "$ref": "#/definitions/textbox"
        }
      ]
    }
  }
}

This schema does not ensure that all items inside the "fields" array of component_properties at the section level have field "component_type": "spacer" or "component_type": "textbox" . For example, "component_type": "another_one" should fail validation.

Please feel free to let me know if any additional information would be helpful. I'd be very appreciative on some guidance here.

You're schema is almost fine – apart from the following details:

  1. The ”type”: “array” inside the sections property should be removed. Just the ”oneOf” should remain. Otherwise the first "oneOf" part (the single element) will never be valid.
  2. The "component_properties" should be of "type": "object" itself and then list the width / display_text / text_color in its "properties" . It looks, like you just copied over an example content.

However, your schema accepts your example because of a typo:

  • In your example, you have a fields property. But in your schema it is called sections . I assume it is supposed to be called fields in both.

Since none of the properties are marked as required , the given example validates fine. There are no constraints for a fields property. If you mark the sections as required , it would complain.


All in all, the following version of your schema should do what you want:

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "type": "object",
  "required": ["component_type", "component_properties"],
  "properties": {
    "component_type": { "const": "section" },
    "component_properties": {
      "type": "object",
      "required": ["section_name", "fields"],
      "properties": {
        "section_name": { "type": "string" },
        "fields": {
          "oneOf": [
            { "$ref": "#/definitions/section_field" },
            { 
              "type": "array",
              "items": { "$ref": "#/definitions/section_field" }
            }
          ]
        }
      }
    }
  },
  "definitions": {
    "spacer": {
      "type": "object",
      "required": ["component_type", "component_properties"],
      "properties": {
        "component_type": { "const": "spacer" },
        "component_properties": {
          "properties": {
            "width": { "type": "number" }
          }
        }
      }
    },
    "textbox": {
      "type": "object",
      "required": ["component_type", "component_properties"],
      "properties": {
        "component_type": { "const": "textbox" },
        "component_properties": {
          "type": "object",
          "properties": {
            "display_text": { "type": "string" },
            "text_color": { "type": "string" }
          }
        }
      }
    },
    "section_field": {
      "oneOf": [
        { "$ref": "#/definitions/spacer" },
        { "$ref": "#/definitions/textbox" }
      ]
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM