Reputation: 941
I am quite new to json schema's and I'm not finding a way to do this.
We are being forced to use draft-4 as we want to use Visual Studio to edit these
We have a json object that has essentially two parts
Part 1
a. tableId (string)
or
b. Schema (string) and a TableName (string)
Part 2
a. ObjectA
or
b. ObjectB
Is there any elegent way to express this in json schema or am I going to have to declare each Object and type by name and create 4 seperate schemas referring to each piece and then essentially have an verbosely expanded version of a oneOf that is essentially "oneof":[{aa},{ab},{ba},{bb}]
UPDATED
I've tried the suggestions but I can't seem to get this to work
Attempt 1. allOf\oneOf
{
"$schema": "http://json-schema.org/draft-04/schema",
"allOf": [
{
"oneOf": [
{
"$ref": "#/definitions/directTableReference"
},
{
"$ref": "#/definitions/tableIdObject"
}
]
},
{
"oneOf": [
{
"$ref": "#/definitions/ObjectA"
},
{
"$ref": "#/definitions/ObjectB"
}
]
}
],
"definitions": {
"directTableReference": {
"type": "object",
"title": "schema directTableReference",
"properties": {
"schema": {
"type": "string"
},
"tableName": {
"type": "string"
}
},
"required": [
"schema",
"tableName"
]
},
"tableIdObject": {
"type": "object",
"title": "schema tableIdObject",
"properties": {
"tableId": {
"type": "string"
}
},
"required": [
"tableId"
]
},
"ObjectA": {
"type": "object",
"title": "schema objectA",
"properties": {
"ObjectAName": {
"type": "string"
}
},
"required": [
"ObjectAName"
]
},
"ObjectB": {
"type": "object",
"title": "schema objectB",
"properties": {
"ObjectBName": {
"type": "string"
}
},
"required": [
"ObjectBName"
]
}
}
}
This is incorrect but it is validated. I can see that it hasn't found ObjectAName to be ObjectA as it doesn't show the title in the hover over in visual studio code
{
"$schema": "./testSchema.json",
"ObjectAName":"blah",
"ObjectBName":"blah"
}
Attempt 2 - oneOf\allOf with all 4 combinations
Even this doesn't work
{
"$schema": "http://json-schema.org/draft-04/schema",
"title": "testSchema",
"oneOf": [
{
"allOf": [
{
"$ref": "#/definitions/directTableReference"
},
{
"$ref": "#/definitions/ObjectA"
}
],
"additionalProperties": false
},
{
"allOf": [
{
"$ref": "#/definitions/tableIdObject"
},
{
"$ref": "#/definitions/ObjectA"
}
],
"additionalProperties": false
},
{
"allOf": [
{
"$ref": "#/definitions/directTableReference"
},
{
"$ref": "#/definitions/ObjectB"
}
],
"additionalProperties": false
},
{
"allOf": [
{
"$ref": "#/definitions/tableIdObject"
},
{
"$ref": "#/definitions/ObjectB"
}
],
"additionalProperties": false
}
],
"definitions": {
"directTableReference": {
"type": "object",
"title": "schema directTableReference",
"properties": {
"schema": {
"type": "string"
},
"tableName": {
"type": "string"
}
},
"required": [
"schema",
"tableName"
]
},
"tableIdObject": {
"type": "object",
"title": "schema tableIdObject",
"properties": {
"tableId": {
"type": "string"
}
},
"required": [
"tableId"
]
},
"ObjectA": {
"type": "object",
"title": "schema objectA",
"properties": {
"ObjectAName": {
"type": "string"
}
},
"required": [
"ObjectAName"
]
},
"ObjectB": {
"type": "object",
"title": "schema objectB",
"properties": {
"ObjectBName": {
"type": "string"
}
},
"required": [
"ObjectBName"
]
}
}
}
This is now seen as invalid and actually as the directTableReference Object
{
"tableId": "blah",
"ObjectAName": "blah"
}
Struggling to see the point of allOf when it basically makes impossible objects, but surely I'm missing a trick here.
Is there no way to actually reuse these objects or is there no way to do this in draft-4. Does it help if I can go to draft-7?
Thanks for any help
Upvotes: 0
Views: 1143
Reputation: 941
Ok, @ether gave me confidence in the right direction and just writing this up here with the final actual schema in case it helps someone else trying to "merge" or "blend" json objects together with allOf
The solution was
So the final working schema was this
{
"$schema": "http://json-schema.org/draft-04/schema",
"$id": "https://blah.com/test",
"title": "testSchema",
"oneOf": [
{
"title":"Ba",
"allOf": [
{
"$ref": "#/definitions/directTableReference"
},
{
"$ref": "#/definitions/ObjectA"
}
],
"properties": {
"schema":{},
"tableName":{},
"ObjectAName":{}
},
"additionalProperties": false
},
{
"title":"Aa",
"allOf": [
{
"$ref": "#/definitions/tableIdObject"
},
{
"$ref": "#/definitions/ObjectA"
}
],
"properties": {
"tableId":{},
"ObjectAName":{}
},
"additionalProperties": false
},
{
"title":"Bb",
"allOf": [
{
"$ref": "#/definitions/directTableReference"
},
{
"$ref": "#/definitions/ObjectB"
}
],
"properties": {
"schema":{},
"tableName":{},
"ObjectBName":{}
},
"additionalProperties": false
},
{
"title":"Ba",
"allOf": [
{
"$ref": "#/definitions/tableIdObject"
},
{
"$ref": "#/definitions/ObjectB"
}
],
"properties": {
"tableId":{},
"ObjectBName":{}
},
"additionalProperties": false
}
],
"definitions": {
"directTableReference": {
"type":"object",
"properties": {
"schema": {
"title": "schema",
"type": "string"
},
"tableName": {
"title": "tableName",
"type": "string"
}
},
"required": [
"schema",
"tableName"
]
},
"tableIdObject": {
"type":"object",
"properties": {
"tableId": {
"title": "tableIdObject",
"type": "string"
}
},
"required": [
"tableId"
]
},
"ObjectA": {
"type":"object",
"properties": {
"ObjectAName": {
"title": "ObjectA",
"type": "string"
}
},
"required": [
"ObjectAName"
]
},
"ObjectB": {
"type":"object",
"properties": {
"ObjectBName": {
"title": "ObjectB",
"type": "string"
}
},
"required": [
"ObjectBName"
]
}
}
}
These are now valid
{
"schema":"blah",
"tableName": "blah",
"ObjectAName": "blah"
}
{
"tableId": "blah",
"ObjectAName": "blah",
}
{
"tableId": "blah",
"ObjectBName": "blah",
}
and these are not
{
"tableId": "blah",
"ObjectAName": "blah",
"ObjectBName": "blah",
}
{
"tableId": "blah",
"blah":"blah"
}
Upvotes: 1
Reputation: 53996
Sure, you should be able to do that by combining definitions
and $ref
with allOf
, anyOf
and oneOf
.
https://json-schema.org/understanding-json-schema/reference/conditionals.html
https://json-schema.org/understanding-json-schema/structuring.html
The docs refer to $defs
, but in draft4 that was called definitions
.
So, something like:
definitions:
tableId:
...
Schema:
...
ObjectA:
...
ObjectB:
...
ObjectC:
...
allOf:
- anyOf:
- $ref: '#/definitions/tableId'
- allOf:
- $ref: '#/definitions/Schema'
- $ref: '#/definitions/TableName'
- anyOf:
- allOf:
- $ref: '#/definitions/ObjectA'
- $ref: '#/definitions/ObjectB'
- $ref: '#/definitions/ObjectC'
- allOf:
- $ref: '#/definitions/ObjectA'
- $ref: '#/definitions/ObjectD'
Upvotes: 1