I'm having trouble trying to create a schema that makes use of both oneOf and a common referenced sub-schema, in order to avoid having to duplicate parts of the schema.
The JSON that the schema should be validating against looks as follows:
{
"createdDate": "2015-01-20T17:10:05Z",
"createdBy": "testUser",
"lastModifiedDate": "2015-01-20T17:10:05Z",
"lastModifiedBy": "testUser",
"fileUrl": {
"path": "/path/to/file",
"fileName": "file.pdf"
},
"referenceType": "person",
"fileType": "certificate",
"personId": "12345"
}
From this, the common part is:
{
"createdDate": "2015-01-20T17:10:05Z",
"createdBy": "testUser",
"lastModifiedDate": "2015-01-20T17:10:05Z",
"lastModifiedBy": "testUser",
"fileUrl": {
"path": "/path/to/file",
"fileName": "file.pdf"
}
}
The remaining 3 fields are always the same in name and all required, but the allowed enum values for them will vary.
So the schema for the remaining 3 could be one of the following:
{
"properties": {
"referenceType": {
"type": "string",
"enum": [
"vehicle"
]
},
"fileType": {
"type": "string",
"enum": [
"registration document"
]
},
"vehicleId": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"vehicleId"
]
}
OR
{
"properties": {
"referenceType": {
"type": "string",
"enum": [
"person"
]
},
"fileType": {
"type": "string",
"enum": [
"certificate"
]
},
"personId": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"personId"
]
}
I can't seem to create a schema whereby I can avoid duplicating the common fields, and have the oneOf, and set additionalProperties to false across the whole schema.
With the below example, trying to set additionalProperties to false causes validation errors. Is it possible to do what I'm trying to do?
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"commonFile": {
"properties": {
"createdDate": {
"type": "string",
"format": "date-time"
},
"createdBy": {
"type": "string",
"pattern": "[^ ]"
},
"lastModifiedDate": {
"type": "string",
"format": "date-time"
},
"lastModifiedBy": {
"type": "string",
"pattern": "[^ ]"
},
"fileUrl": {
"type": "object",
"additionalProperties": false,
"properties": {
"path": {
"type": "string",
"pattern": "[^ ]"
},
"fileName": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"path",
"fileName"
]
}
}
}
},
"oneOf": [{
"allOf": [
{"$ref": "#/definitions/commonFile"},
{
"properties": {
"referenceType": {
"type": "string",
"enum": [
"person"
]
},
"fileType": {
"type": "string",
"enum": [
"certificate"
]
},
"personId": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"personId"
]
}
]
}, {
"allOf": [
{"$ref": "#/definitions/commonFile"},
{
"properties": {
"referenceType": {
"type": "string",
"enum": [
"vehicle"
]
},
"fileType": {
"type": "string",
"enum": [
"registration document"
]
},
"vehicleId": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"vehicleId"
]
}
]
}
],
"required": [
"createdDate",
"createdBy",
"lastModifiedDate",
"lastModifiedBy",
"fileUrl",
"referenceType",
"fileType"
]
}
I recommend not setting additionalProperties to false. It is usually best just to quietly ignore properties that are not defined. The following schema is what you would have to do to accomplish your goal.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"createdDate": { "type": "string", "format": "date-time" },
"createdBy": { "type": "string", "pattern": "[^ ]" },
"lastModifiedDate": { "type": "string", "format": "date-time" },
"lastModifiedBy": { "type": "string", "pattern": "[^ ]" },
"fileUrl": {
"type": "object",
"additionalProperties": false,
"properties": {
"path": { "type": "string", "pattern": "[^ ]" },
"fileName": { "type": "string", "pattern": "[^ ]" }
},
"required": ["path", "fileName"]
},
"referenceType": { "type": "string" },
"fileType": { "type": "string" },
"personId": {},
"vehicleId": {}
},
"additionalProperties": false,
"anyOf": [
{
"properties": {
"referenceType": { "enum": ["person"] },
"fileType": { "enum": ["certificate"] },
"personId": { "type": "string", "pattern": "[^ ]" }
},
"required": ["personId"],
"not" : { "required": ["vehicleId"] }
},
{
"properties": {
"referenceType": { "enum": ["vehicle"] },
"fileType": { "enum": ["registration document"] },
"vehicleId": { "type": "string", "pattern": "[^ ]" }
},
"required": ["vehicleId"],
"not" : { "required": ["personId"] }
}
],
"required": ["createdDate", "createdBy", "lastModifiedDate", "lastModifiedBy", "fileUrl", "referenceType", "fileType"]
}
The first thing I did was remove all the extraneous allOfs. Only one anyOf is needed. I defined the common properties in the main schema. The variations are described in the anyOf clause.
If you set additionalProperties to false, an additional schema (such as allOf, oneOf, and anyOf) can not introduce new properties. This means that all properties that are going to be allowed in this schema must be included in the schema that declares additionalProperties to be false. That is why I declared referenceType, fileType, personId, and vechicleId in the main schema.
The problem now is that additionalProperties no longer excludes vehicleId when referenceType is person or personId when referenceType is vehicle. To make sure this isn't allowed, I added the not clauses.
If were you add a third variation, restricting additional properties gets even more difficult. It's not just adding an additional referenceType to the anyof schema array. You also have to add new properties to the main schema and disallow those new types for all of the existing referenceTypes. You have to make changes all over the schema instead of just the area that is changing. This is why setting additionalProperties to false is generally not the best idea.
Related
I configured the json schema and it looked like this:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"organisationId": {
"type": "string"
},
"clientId": {
"type": "string"
},
"issuer": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"createdDate": {
"type": "string",
"format": "date-time"
},
"lastModifiedDate": {
"type": "string",
"format": "date-time"
},
"consentId": {
"type": "string"
},
"internalStatus": {
"type": "string",
"enum": [
"AUTHORISED",
"AWAITING_AUTHORISATION",
"REJECTED",
"TIMEOUT_EXPIRED",
"OVERDUE",
"REVOKED"
]
},
"permissions": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"approverType": {
"type": "string",
"enum": [
"AND",
"OR"
]
},
"status": {
"type": "string",
"enum": [
"AUTHORISED",
"AWAITING_AUTHORISATION",
"REJECTED",
"REVOKED",
"CONSUMED"
]
},
"statusUpdateDateTime": {
"type": "string",
"format": "date-time"
},
"expirationDateTime": {
"type": "string",
"format": "date-time"
},
"resourceGroups": {
"uniqueItems": true,
"oneOf": [
{
"type": "array"
},
{
"type": "null"
}
],
"items": [
{
"type": "object",
"properties": {
"resourceGroupId": {
"type": "integer"
},
"permissions": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"resources": {
"type": "array",
"uniqueItems": true,
"items": [
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"AVAILABLE",
"UNAVAILABLE",
"TEMPORARY_UNAVAILABLE",
"PENDING_AUTHORISATION"
]
},
"additionalInfos": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
}
}
]
},
"type": {
"type": "string",
"enum": [
"CUSTOMERS_PERSONAL_IDENTIFICATIONS",
"CUSTOMERS_PERSONAL_QUALIFICATION",
"CUSTOMERS_PERSONAL_ADITTIONALINFO",
"CUSTOMERS_BUSINESS_IDENTIFICATIONS",
"CUSTOMERS_BUSINESS_QUALIFICATION",
"CUSTOMERS_BUSINESS_ADITTIONALINFO",
"CAPITALIZATION_TITLES",
"PENSION",
"DAMAGES_AND_PEOPLE_PATRIMONIAL",
"DAMAGES_AND_PEOPLE_AERONAUTICAL",
"DAMAGES_AND_PEOPLE_NAUTICAL",
"DAMAGES_AND_PEOPLE_NUCLEAR",
"DAMAGES_AND_PEOPLE_OIL",
"DAMAGES_AND_PEOPLE_RESPONSABILITY",
"DAMAGES_AND_PEOPLE_TRANSPORT",
"DAMAGES_AND_PEOPLE_FINANCIAL_RISKS",
"DAMAGES_AND_PEOPLE_RURAL",
"DAMAGES_AND_PEOPLE_AUTO",
"DAMAGES_AND_PEOPLE_HOUSING",
"DAMAGES_AND_PEOPLE_PEOPLE",
"DAMAGES_AND_PEOPLE_ACCEPTANCE_AND_BRANCHES_ABROAD"
]
},
"hidden": {
"type": "boolean"
},
"resourceId": {
"type": "string"
}
}
}
]
},
"additionalInfos": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
}
}
]
},
"type": {
"type": "string",
"enum": [
"ACCOUNT",
"CREDIT_CARD_ACCOUNT",
"LOAN",
"INVOICE_FINANCING",
"UNARRANGED_ACCOUNT_OVERDRAFT",
"FINANCING",
"RESOURCE",
"CUSTOMER"
]
}
},
"required": [
"permissions",
"type"
]
}
]
},
"approvers": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"AUTHORISED",
"AWAITING_AUTHORISATION",
"REJECTED",
"REVOKED",
"CONSUMED"
]
},
"approverId": {
"type": "string"
}
},
"required": [
"approverId"
]
}
]
},
"loggedUser": {
"type": "object",
"properties": {
"document": {
"type": "object",
"properties": {
"identification": {
"type": "string"
},
"rel": {
"type": "string"
}
},
"required": [
"identification",
"rel"
]
}
},
"required": [
"document"
]
},
"businessEntity": {
"type": "object",
"properties": {
"document": {
"type": "object",
"properties": {
"identification": {
"type": "string"
},
"rel": {
"type": "string"
}
},
"required": [
"identification",
"rel"
]
}
},
"required": [
"document"
]
}
},
"required": [
"organisationId",
"clientId",
"consentId",
"permissions",
"approverType",
"status",
"statusUpdateDateTime",
"expirationDateTime",
"loggedUser"
]
},
"links": {
"type": "object",
"properties": {
"self": {
"type": "string"
},
"first": {
"type": "string"
},
"prev": {
"type": "string"
},
"next": {
"type": "string"
},
"last": {
"type": "string"
}
},
"required": [
"self"
]
},
"meta": {
"type": "object",
"properties": {
"totalRecords": {
"type": "integer"
},
"totalPages": {
"type": "integer"
}
},
"required": [
"totalRecords",
"totalPages"
]
}
}
}
Note that the "resources" array is not required, it is not mandatory.
However... when I run my test and it returns an empty array in "resources":
"resourceGroupId":1,
"permissions":[
"CUSTOMERS_PERSONAL_QUALIFICATION_READ",
"CUSTOMERS_PERSONAL_IDENTIFICATIONS_READ"
],
"resources":[],
"type":"CUSTOMER"
}
I get the following message:
"#/data/resourceGroups/0/resources: failed schema #/properties/data/properties/resourceGroups/items/0/properties/resources: 1 item required; only 0 were supplied."
I don't understand how 1 item is required if the array is not required.
and still have( "uniqueItems": true
)
which in theory would accept a [] in the return, according to the Json schema documentation.
I've tried passing minItems=0 and many other things and nothing has worked.
This looks like a combination of a bug in the validator you are using and an incorrect usage of items. The good news is that when you use items correctly, the bug will probably not apply.
The items keyword has two forms: one that takes a single schema and the other that takes an array of schemas. The form must people need most of the time is the single schema form.
{
"type": "array",
"items": { "type": "string" }
}
This schemas asserts that every item in the array is a string.
{
"type": "array",
"items": [
{ "type": "string" },
{ "type": "number" }
]
}
This schema asserts that the first item in the array is a string and the second is a number. However, it should not require that those items are present or assert anything on the rest of the items in the array. So, the bug is that your validator seems to require those values when it shouldn't.
But, that bug shouldn't affect you because you I'm sure you really meant to use the single schema version of items that validates all the items in the array against the schema. Just remove the [ and ] and your schema should work as you expected.
I am attempting to validate the following JSON file:
{
"Transaction": {
"Header": {
"Workflow": "Rejection",
"Job-Offer": {
"Offer-Status": "New",
"Datetime-Offered": "2017-12-15T16:00:00",
"Accepted": "YES",
"Datetime-Accepted": "2017-12-15T16:00:00"
}
}
}
}
against the following schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Schema",
"description": "Schema",
"$ref": "#/defs/Schema",
"defs": {
"Schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"Transaction": {
"$ref": "#/defs/Transaction"
}
},
"required": [
"Transaction"
],
"title": "Schema"
},
"Transaction": {
"type": "object",
"additionalProperties": false,
"properties": {
"Transaction-Header": {
"$ref": "#/defs/Transaction-Header"
}
},
"required": [
"Transaction-Header"
],
"title": "Transaction"
},
"Transaction-Header": {
"type": "object",
"additionalProperties": false,
"properties": {
"Workflow": {
"type": "string",
"enum": [
"Offer",
"Transfer",
"Acceptance",
"Rejection",
"Cancellation",
"Update"
]
},
"Job-Offer": {
"$ref": "#/defs/JobOffer"
}
},
"required": [
"Workflow"
],
"title": "Transaction-Header"
},
"JobOffer": {
"description": "Job Offer.",
"type": "object",
"additionalProperties": true,
"properties": {
"Offer-Status": {
"type": "string",
"enum": [
"New",
""
]
},
"Datetime-Offered": {
"type": "string",
"format": "date-time"
},
"Accepted": {
"type": "string",
"enum": [
"YES",
"NO",
""
]
},
"Datetime-Accepted": {
"type": "string",
"format": "date-time"
},
"Reason-Rejected": {
"type": "string",
"minLength": 0,
"maxLength": 30
},
"Offer-Cancelled": {
"type": "string",
"enum": [
"YES",
"NO",
""
]
},
"Datetime-Cancelled": {
"type": "string",
"format": "date-time"
}
},
"allOf": [
{ "$ref": "#/defs/JOBACCEPT" },
{ "$ref": "#/defs/JOBREJECT" }
],
"required": [
"Offer-Status"
],
"title": "JobOffer"
},
"JOBACCEPT": {
"properties": {
"Workflow": { "enum": [ "Acceptance" ] }
},
"required": [
"Accepted",
"Datetime-Accepted"
],
},
"JOBREJECT": {
"properties": {
"Workflow": { "enum": [ "Rejection" ] }
},
"required": [
"Reason-Rejected"
],
}
}
}
What I am after is:
If the Workflow of "Acceptance" is selected, the fields under JOBACCEPT are required.
If the Workflow of "Rejection" is selected, the fields under JOBREJECT are required.
I have tried many different combinations of oneOf, allOf, anyOf, if-then-else but nothing seems to work correctly.
Anyone have any ideas what needs to be done?
Re-worked json inline:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"type": "object",
"properties": {
"Transaction": {
"type": "object",
"properties": {
"Transaction-Header": {
"type": "object",
"properties": {
"Workflow": {
"type": "string",
"enum": [
"Offer",
"Transfer",
"Acceptance",
"Rejection",
"Cancellation",
"Update"
]
},
"Job-Offer": {
"type": "object",
"properties": {
"Offer-Status": {
"type": "string",
"enum": [
"New",
""
]
},
"Datetime-Offered": {
"type": "string",
"format": "date-time"
},
"Accepted": {
"type": "string",
"enum": [
"YES",
"NO",
""
]
},
"Datetime-Accepted": {
"type": "string",
"format": "date-time"
},
"Reason-Rejected": {
"type": "string",
"minLength": 0,
"maxLength": 30
},
"Offer-Cancelled": {
"type": "string",
"enum": [
"YES",
"NO",
""
]
},
"Datetime-Cancelled": {
"type": "string",
"format": "date-time"
}
},
"required": [
"Offer-Status"
]
},
"readOnly": true
},
"required": [
"Workflow"
]
}
},
"required": [
"Transaction-Header"
]
}
},
"allOf": [
{
"if": {
"properties": {
"Transaction": {
"properties": {
"Transaction-Header": {
"properties": {
"Workflow": {
"enum": [
"Acceptance"
]
}
},
"required": [
"Workflow"
]
}
}
}
}
},
"then": {
"properties": {
"Transaction": {
"properties": {
"Transaction-Header": {
"properties": {
"Job-Offer": {
"properties": {},
"required": [
"Accepted",
"Datetime-Accepted"
]
}
}
}
}
}
}
}
}
],
"required": [
"Transaction"
]}
You had the right idea. The problem is where you've placed the allOf with your conditionals. You have it in the "JobOffer" schema, but are trying to set constraints on the "Workflow" property which is in the "Transaction-Header" schema. There is no way to reference a property that is higher up in the JSON tree structure, so you need to move the allOf up into the "Transaction-Header" schema so you can set constraints on the "Workflow" property.
Now that it's in the right place, the best way to express your conditional constraints is with if/then. The context of the if/then is now the the "Transaction-Header" schema, so the then schemas needs to not just say what properties are required, they need to declare that those properties are in the "Job-Offer" object.
{
...
"defs": {
...
"Transaction-Header": {
...
"allOf": [
{ "$ref": "#/defs/JOBACCEPT" },
{ "$ref": "#/defs/JOBREJECT" }
]
},
"JOBACCEPT": {
"if": {
"type": "object",
"properties": {
"Workflow": { "enum": ["Acceptance"] }
},
"required": ["Workflow"]
},
"then": {
"properties": {
"Job-Offer": {
"required": ["Accepted", "Datetime-Accepted"]
}
}
}
},
"JOBREJECT": { ... Similar to JOBACCEPT ... }
}
}
You're abstracting everything away into definitions *, so it's tricky to express conditionals that reference things multiple layers deep. If you inline all the definitions, it gets a little easier to see what needs to be done.
The if/then keywords need to be at the level of 'Transaction'. In pseudocode:
"if the property 'Header' exists (i.e. required) and its value is ... (const), then require property ... with value (type=object, required properties=[...], property definitions=...)", and so on.
* by the way, in version 2020-12 the definitions keyword is $defs -- it may work the way you have it, but implementations will be unable to validate the schemas undef defs as they won't recognize them there, so some errors can slip through and be harder to find.
I am very new to JSON Schema. I have a requirement in a array few items are mandatory and few are optional. Each item is having different validation rules. All the items may not come is sequence order. I have to create this schema only in draft04 version.
My JSON message is as below.
{
"Event": {
"AttributeList": [
{
"Attribute": {
"name": "OrderID",
"value": "String"
}
},
{
"Attribute": {
"name": "txnid",
"value": "Strinnkjnjknlg"
}
},
{
"Attribute": {
"name": "Appid",
"value": "Stg"
}
},
{
"Attribute": {
"name": "txnswitch",
"value": "false"
}
}
]
}
}
I have to build a JSON schema where Attributes with the below conditions:
The items(Attribute) under the Attribute list can have both mandatory and optional which is not working.Here "name" Appid and OrderID are mandatory and rest of them are optional ones.
The items(Attribute) can be any sequence/order.
Items shouldn't be repeated.
I have written the below schema but couldn't achieve all the conditions.
JSON Schema is as follows
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Event": {
"type": "object",
"properties": {
"AttributeList": {
"type": "array",
"uniqueItems": true,
"items": {
"allOf": [
{
"type": "object",
"properties": {
"Attribute": {
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"OrderID"
]
},
"value": {
"type": "string",
"maxLength": 16
}
},
"required": [
"name",
"value"
],
"optional": false
}
},
"required": [
"Attribute"
],
"optional": false
},
{
"type": "object",
"properties": {
"Attribute": {
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"txnid"
]
},
"value": {
"type": "string",
"maxLength": 35
}
},
"required": [
"name",
"value"
],
"optional": true
}
},
"required": [
"Attribute"
],
"optional": true
},
{
"type": "object",
"properties": {
"Attribute": {
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"Appid"
]
},
"value": {
"type": "string",
"maxLength": 8
}
},
"required": [
"name",
"value"
],
"optional": false
}
},
"required": [
"Attribute"
],
"optional": false
},
{
"type": "object",
"properties": {
"Attribute": {
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"txnswitch"
]
},
"value": {
"type": "string",
"maxLength": 28
}
},
"required": [
"name",
"value"
],
"optional": true
}
},
"required": [
"Attribute"
],
"optional": true
}
]
}
}
},
"required": [
"AttributeList"
]
}
},
"required": [
"Event"
]
}
This schema doesn't work as expected.
Your schema isn't working because prefixItems isn't supported with draft4 (which is what your $schema keyword indicates), plus the schema under prefixItems will only be applied to the first item, not all items.
You can achieve what you need with contains combined with minContains and maxContains. For the mandatory items, use minContains: 1 and for the optional ones, use minContains: 0. You can set maxContains: 1 for both of these to ensure each item type can't appear twice.
https://json-schema.org/understanding-json-schema/reference/array.html#contains
You'll need an evaluator that supports at least draft2019-09 for minContains and maxContains.
I am trying to define a json schema which has a common enum type for a number of objects and then depending on which enum is selected, define the possible combinations of enums and also additional elements that are needed.
The example has FurnitureData with {IDNumber, Color, Furniture Type} and then depending on the Type selected from a enum list, gets a function assigned with different enums. I also put in an example of "Person assigned" as an extra element.
I think I did this correctly using anyof and const. But, when I test with XMLSpy Pro 2020, it generates invalid json examples and also when I try to validate an invalid example, it passes.... so, 1) did I express this well ? 2) what am I doing wrong ? 3) is there a better way ? 4) Is it the tool or the json schema ?
Please help.
JSON Schema :
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Comment describing your JSON Schema",
"type": "object",
"properties": {
"FurnitureData": {
"type": "array",
"items": {
"type": "object",
"properties": {
"IDNumber": {
"type": "object",
"description": "Unique identifier",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"maxLength": 16
},
"readOnly": {
"type": "boolean",
"default": true
}
}
},
"Color": {
"type": "object",
"description": "Preferred color",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"default": "WOOD",
"enum": [
"BLUE",
"WOOD",
"GREEN"
]
},
"custom value": {
"type": "string",
"maxLength": 32
}
}
},
"Furniture Type": {
"type": "object",
"description": "Kind of Furniture",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"default": "CHAIR",
"enum": [
"LAMP",
"TABLE",
"CHAIR"
]
},
"custom value": {
"type": "string",
"maxLength": 32
}
}
}
},
"required": [
"IDNumber",
"Color",
"Furniture Type"
],
"anyOf": [
{
"properties": {
"Furniture Type": {
"value": {
"const": "LAMP"
}
},
"Function": {
"type": "object",
"description": "Lighting arrangement",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"LIGHT ON",
"LIGHT OFF"
]
}
}
}
},
"required": [
"Furniture Type",
"Function"
]
},
{
"properties": {
"Furniture Type": {
"value": {
"const": "TABLE"
}
},
"Function": {
"type": "object",
"description": "Size of table",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"3' x 4'",
"6' x 4'",
"12' x 4'",
"10' round"
]
}
}
}
},
"required": [
"Furniture Type",
"Function"
]
},
{
"properties": {
"Furniture Type": {
"value": {
"const": "CHAIR"
}
},
"Function": {
"type": "object",
"description": "Planned use",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"WORKSPACE SEAT",
"SPARE SEAT"
]
}
}
},
"Person assigned": {
"type": "object",
"description": "Seating assignment",
"required": [
"value"
],
"properties": {
"value": {
"type": "string"
}
}
}
},
"required": [
"Furniture Type",
"Function",
"Person assigned"
]
}
]
}
}
},
"required": [
"FurnitureData"
]
}
Invalid JSON Example that XMLSpy validates as okay: (it is linked to my schema in the info page)
Lamps should not allow 6x4 as a function...
{
"FurnitureData": [
{
"Color": {
"value": "WOOD",
"readOnly": "a",
"custom value": "a"
},
"IDNumber": {
"value": "a",
"readOnly": true
},
"Furniture Type": {
"value": "LAMP",
"custom value": "a"
},
"Function": {
"value": "6' x 4'",
"custom value": "a"
}
}
]
}
Another Invalid example... Chairs have "Person assigned" and the wrong type value is shown but this validates too...
{
"FurnitureData": [
{
"Color": {
"value": "WOOD",
"readOnly": "a",
"custom value": "a"
},
"IDNumber": {
"value": "a",
"readOnly": true
},
"Furniture Type": {
"value": "CHAIR",
"custom value": "a"
},
"Function": {
"value": "6' x 4'",
"custom value": "a"
}
}
]
}
This is following the recommendation in
See enum section using anyof
Maybe I must use an if-then construct ? Here, I tried with if-then in the any-of but I also get validations of json that allow enums from the other furniture types...
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Comment describing your JSON Schema",
"type": "object",
"properties": {
"FurnitureData": {
"type": "array",
"items": {
"type": "object",
"properties": {
"IDNumber": {
"type": "object",
"description": "Unique identifier",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"maxLength": 16
},
"readOnly": {
"type": "boolean",
"default": true
}
}
},
"Color": {
"type": "object",
"description": "Preferred color",
"required": [
"value",
"readOnly"
],
"properties": {
"value": {
"type": "string",
"default": "WOOD",
"enum": [
"BLUE",
"WOOD",
"GREEN"
]
},
"custom value": {
"type": "string",
"maxLength": 32
}
}
},
"Furniture Type": {
"type": "object",
"description": "Kind of Furniture",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"default": "CHAIR",
"enum": [
"LAMP",
"TABLE",
"CHAIR"
]
},
"custom value": {
"type": "string",
"maxLength": 32
}
}
}
},
"required": [
"IDNumber",
"Color",
"Furniture Type"
],
"anyOf": [
{
"if": {
"properties": {
"Furniture Type": {
"value": {
"const": "LAMP"
}
}
}
},
"then": {
"properties": {
"Function": {
"type": "object",
"description": "Lighting arrangement",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"LIGHT ON",
"LIGHT OFF"
]
}
}
}
},
"required": [
"Function"
]
}
},
{
"if": {
"properties": {
"Furniture Type": {
"value": {
"const": "TABLE"
}
}
}
},
"then": {
"properties": {
"Function": {
"type": "object",
"description": "Size of table",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"3' x 4'",
"6' x 4'",
"12' x 4'",
"10' round"
]
}
}
}
},
"required": [
"Function"
]
}
},
{
"if": {
"properties": {
"Furniture Type": {
"value": {
"const": "CHAIR"
}
}
}
},
"then": {
"properties": {
"Function": {
"type": "object",
"description": "Planned use",
"required": [
"value"
],
"properties": {
"value": {
"type": "string",
"enum": [
"WORKSPACE SEAT",
"SPARE SEAT"
]
}
}
},
"Person assigned": {
"type": "object",
"description": "Seating assignment",
"required": [
"value"
],
"properties": {
"value": {
"type": "string"
}
}
}
},
"required": [
"Function",
"Person assigned"
]
}
}
]
}
}
},
"required": [
"FurnitureData"
]
}
The values of a JSON Schema properties object are subschemas (JSON Schemas in their own right).
Knowing that, if you take your subschema at properties.FurnitureData.anyOf[1].properties['Furniture Type'], and you take that as a schema... it actually doesn't express any constraints.
The subschema at that location from your schema is...
{
"value": {
"const": "TABLE"
}
}
whereas it needs to be...
{
"properties":{
"value": {
"const": "TABLE"
}
}
}
The easiest way to debug this sort of issue is test your assumptions.
You assumed that allOf[1] and allOf[2] should fail, so replace those subschemas with false (booleans are valid schemas).
In doing so, you find out the assumption is wrong, and allOf[1] is valid. Of course you expect the const to be picked up, and therefore this subschema to fail, but it isn't picked up because you were missing properties and value isn't a valid JSON Schema keyword.
You can run these sort of quick tests using https://jsonschema.dev/s/Xt1Yi
Is it possible to make a field required/non-required depending on other field value in JSON schema?
JSON schema contains mode field. If it equals to 'release' or 'debug', the file_path is not required. If it equals to 'custom' it is required.
"mode": {
"enum": [
"debug",
"release",
"custom"
],
"id": "mode",
"required": true,
"type": "string"
},
"file_path": {
"id": "file_path",
"required": false,
"type": "string"
}
There is a solution for JSON Schema draft 7:
{
"build": {
"type": "object",
"id": "build",
"oneOf": [
{
"$ref": "#/definitions/ReleaseDebug"
},
{
"$ref": "#/definitions/Custom"
}
]
}
},
"definitions": {
"ReleaseDebug": {
"required": ["mode"],
"properties": {
"mode": {
"type": "string",
"enum": [
"debug",
"release"
],
"id": "mode"
}
}
},
"Custom": {
"required": ["mode", "file_path"],
"properties": {
"mode": {
"type": "string",
"enum": [
"custom"
],
"id": "mode"
},
"file_path": {
"type": "string",
"id": "file_path"
},
}
}
}