Alex Blekhman
Alex Blekhman

Reputation: 3985

JSON schema draft-04: extending for specific "enum" value

I'm trying to extend JSON schema, which defines an enum:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "definitions": {
    "objType": {
      "enum": [ "A", "B" ]
    },
    "baseType": {
      "type": "object",
      "properties": {
        "category": { "$ref": "#/definitions/objType" }
      }
    }
  },
  "properties": {
    "A": {
      "allOf": [
        { "$ref": "#/definitions/baseType" },
        /* how to restrict inherited `category' to "A"? */
        { /* properties specific to A */ }
      ]
    },
    "B": {
      "allOf": [
        { "$ref": "#/definitions/baseType" },
        /* how to restrict inherited `category' to "B"? */
        { /* properties specific to B */ }
      ]
    }
  }
}

I'm not sure how restrict inherited enum property to specific value. For example:

// passes validation
{
  "category": "A",
  "prop_A": "blah A"
}

// fails because `prop_A' is not valid property for category "B"
{
  "category": "B",
  "prop_A":  "blah A"
}

Thanks.

Upvotes: 0

Views: 2766

Answers (3)

Yahor
Yahor

Reputation: 681

With Schema Draft v6 this seems to be possible:

{
    "$schema": "http://json-schema.org/draft-06/schema#",
    "type": "object",
    "oneOf": [
        {
            "additionalProperties": false,
            "properties": {
                "category": {
                    "type": "string",
                    "const": "A"
                },
                "prop_A": {
                    "type": "string"
                }
            }
        },
        {
            "additionalProperties": false,
            "properties": {
                "category": {
                    "type": "string",
                    "const": "B"
                },
                "prop_B": {
                    "type": "string"
                }
            }
        }
    ]
}

Upvotes: 0

Henry Andrews
Henry Andrews

Reputation: 693

JSON Schema is a constraint system rather than an object oriented system, so "inheritance" as a concept doesn't fit very well. See https://github.com/json-schema-org/json-schema-org.github.io/issues/148 for more information.

However, in your case, I think that the constraint system is exactly what you want. In a constraint system, you can always add more constraints, but you can never remove them. So restricting an enum to a subset of its "inherited" values is as simple as using "allOf" to add a constraint of a single-valued enum over top of the original two-valued enum.

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "definitions": {
    "objType": {
      "enum": [ "A", "B" ]
    },
    "baseType": {
      "type": "object",
      "properties": {
        "category": { "$ref": "#/definitions/objType" }
      }
    }
  },
  "properties": {
    "A": {
      "allOf": [
        { "$ref": "#/definitions/baseType" },
        { "objType": { "enum": [ "A" ] }.
        { /* properties specific to A */ }
      ]
    },
    "B": {
      "allOf": [
        { "$ref": "#/definitions/baseType" },
        { "objType": { "enum": [ "B" ] }.
        { /* properties specific to B */ }
      ]
    }
  }
}

You just need to further constrain the enum for each type of property at the point where it is actually used.

Upvotes: 2

jq170727
jq170727

Reputation: 14715

In the Building a mount point schema example they do this a little differently. Each storage refers to one of several types of objects:

"properties": {
    "storage": {
        "type": "object",
        "oneOf": [
            { "$ref": "#/definitions/diskDevice" },
            { "$ref": "#/definitions/diskUUID" },
            { "$ref": "#/definitions/nfs" },
            { "$ref": "#/definitions/tmpfs" }
        ]
    },

and each of the object types includes a type enum with a different value. e.g. diskDevice specifies type in this way

"properties": {
    "type": { "enum": [ "disk" ] },
    "device": {
        "type": "string",
        "pattern": "^/dev/[^/]+(/[^/]+)*$"
    }

whereas nfs specifies type this way

"properties": {
    "type": { "enum": [ "nfs" ] },
    "remotePath": {
        "type": "string",
        "pattern": "^(/[^/]+)+$"
    },

Perhaps you could consider refactoring your schema along those lines.

Upvotes: 0

Related Questions