Jonathan Camilleri Jonathan Camilleri - 2 months ago 6
JSON Question

Is it possible to have common properties before oneOf?

I have this json schema that has an array that contains multiple object, and each object differs slightly from the others based on certain patterns.

Example.

[
{
"ID": "pgID",
"Name": "John",
"Surname": "Doe",
"ProjectsInvolved": [
"My Project",
"My Project 2"
]
},
{
"ID": "jtID",
"Name": "John",
"Surname": "Doe",
"WorksOn": [
"Monday",
"Thursday"
]
}
]


The json schema for that would be:

{
"$schema": "http://json-schema.org/draft-04/schema",
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"ID": {
"type": "string",
"pattern": "^(pg)\\w*$"
},
"Name": {
"type": "string"
},
"Surname": {
"type": "string"
},
"ProjectsInvolved": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
{
"type": "object",
"properties": {
"ID": {
"type": "string",
"pattern": "^(jt)\\w*$"
},
"Name": {
"type": "string"
},
"Surname": {
"type": "string"
},
"WorksOn": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
]
},
"additionalProperties": false
}


My issue is that although the real json is similar, it has many more items, and it is poised to grow larger as more time passes. Therefore I must ask, is it possible for the schema to group the identical elements Name, and Surname, and only have the ID and the arrays in the oneOf?

An Example of the suggested schema:

{
"$schema": "http://json-schema.org/draft-04/schema",
"type": "array",
"items": {
"type": "object",
"properties": {
"Name": {
"type": "string"
},
"Surname": {
"type": "string"
},
"oneOf": [
{
"ID": {
"type": "string",
"pattern": "^(pg)\\w*$"
},
"ProjectsInvolved": {
"type": "array",
"items": {
"type": "string"
}
}
},
{
"ID": {
"type": "string",
"pattern": "^(jt)\\w*$"
},
"WorksOn": {
"type": "array",
"items": {
"type": "string"
}
}
}
]
}
},
"additionalProperties": false
}

Answer

Generally, you want to define the common stuff upfront and the special conditions after. This makes the schema easier to read and results in better error messages.

In this example, if "ProjectsInvolved" is present, then "ID" must start with "pg" and "WorksOn" can not be present. And, if "WorksOn" is present, then "ID" must start with "jt" and "ProjectsInvolved" can not be present.

It is possible to something like this with oneOf or anyOf as well, but you generally get better error messaging with dependencies.

{
  "$schema": "http://json-schema.org/draft-04/schema",
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "ID": { "type": "string" },
      "Name": { "type": "string" },
      "Surname": { "type": "string" },
      "ProjectsInvolved": {
        "type": "array",
        "items": { "type": "string" }
      },
      "WorksOn": {
        "type": "array",
        "items": { "type": "string" }
      }
    },
    "dependencies": {
      "ProjectsInvolved": {
        "properties": {
          "ID": { "pattern": "^(pg)\\w*$" }
        },
        "not": { "required": ["WorksOn"] }
      },
      "WorksOn": {
        "properties": {
          "ID": { "pattern": "^(jt)\\w*$" }
        },
        "not": { "required": ["ProjectsInvolved"] }
      }
    }
  },
  "additionalProperties": false
}