JSON Schema required field depending on other field value - json

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"
},
}
}
}

Related

array not required returns the message: "1 item required; only 0 were given" in the json schema

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.

JSON Schema validation for different property values

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.

Using arrays items in JSON Schema

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.

JSON-Schema add property to the item conditionally

I have the following JSON data
[
{
"type": "social_media_profiles",
"data": {
"profiles": [
{
"key": "twitter",
"data": "username",
"field": "handle",
"label": "Tweet"
},
{
"key": "customLink",
"data": "abc",
"field": "url",
"label": "Click",
"color": {
"button": "red",
"text": "green",
"border": "yellow"
}
}
]
}
}
]
and following jsong schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"additionalProperties": false,
"items": {
"type": "object",
"required": ["type", "data"],
"additionalProperties": false,
"properties": {
"type": {
"type": "string",
"enum": [
"social_media_profiles"
]
},
"data": {
"type": "object"
}
},
"allOf": [
{
"if": {
"properties": {
"type": {
"const": "social_media_profiles"
}
}
},
"then": {
"properties": {
"data": {
"type": "object",
"required": ["profiles"],
"additionalProperties": false,
"properties": {
"profiles": {
"type": "array",
"items": {
"type": "object",
"required": ["data", "field", "key"],
"additionalProperties": false,
"properties": {
"data": {
"type": "string",
"description": "Data contains either profile url, handle id, etc."
},
"field": {
"type": "string",
"enum": ["url", "handle", "id", "tel"],
"description": "Type of field value."
},
"key": {
"type": "string",
"description": "Social media name used to distinguish each social network"
},
"label": {
"type": "string",
"description": "Label to display on the landing page"
}
},
"allOf": [
{
"if": {
"properties": {
"key": {
"const": "customLink"
}
}
},
"then": {
"properties": {
"color": {
"type": "object",
"additionalProperties": false,
"required": [],
"properties": {
"button": {
"type": "string"
},
"text": {
"type": "string"
},
"border": {
"type": "string"
}
}
}
}
}
}
]
}
}
}
}
}
}
}
]
}
}
I want to add new property color to the profiles item based on the condition when key of the item is customLink.
If key is not customLink then color property should not be there.
Validating the schema from https://www.jsonschemavalidator.net/ is giving error
Found 2 error(s)
Message: JSON does not match all schemas from 'allOf'. Invalid schema indexes: 0.
Schema path: #/items/allOf
Message: JSON does not match schema from 'then'.
Schema path: #/items/allOf/0/then/then
How can I append new property conditionally based on the sibling property value?
In your profiles.items schema, you defined additionalProperties: false.
additionalProperties depends on the properties defined in the same schema object, meaning that color would always be dissallowed.
You can separate out your concerns into "what properties are allowed", and "if their values are valid".
Moving the validation for the color object into profiles.properties allows you to maintain additionalProperties: false in that object level.
The schema values of the properties object are only applied to the instance location for the keys, if they exist (hence needing to use required to require that specific keys are... required).
Having simplified the condional section, you end up with a cleaner Schema.
You now only need to define the condition under which color is required, without worrying about what the value should look like.
Sudo code: if key is customLink, then require color, else dissallow color.
{
"if": {
"properties": {
"key": {
"const": "customLink"
}
}
},
"then": {
"required": [
"color"
]
},
"else": {
"not": {
"required": [
"color"
]
}
}
}
Using not, you can invert the validation result of the applied subschema, which is what you need to do when you want to define that a specific property is NOT allowed.
Here's a live demo to play with: https://jsonschema.dev/s/C9V6N
And for prosperity, here's the full schema, with one or two redundancies removed.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"type": "object",
"required": [
"type",
"data"
],
"additionalProperties": false,
"properties": {
"type": {
"type": "string",
"enum": [
"social_media_profiles"
]
},
"data": {
"type": "object"
}
},
"allOf": [
{
"properties": {
"data": {
"type": "object",
"required": [
"profiles"
],
"additionalProperties": false,
"properties": {
"profiles": {
"type": "array",
"items": {
"type": "object",
"required": [
"data",
"field",
"key"
],
"additionalProperties": false,
"properties": {
"data": {
"type": "string",
"description": "Data contains either profile url, handle id, etc."
},
"field": {
"type": "string",
"enum": [
"url",
"handle",
"id",
"tel"
],
"description": "Type of field value."
},
"key": {
"type": "string",
"description": "Social media name used to distinguish each social network"
},
"label": {
"type": "string",
"description": "Label to display on the landing page"
},
"color": {
"type": "object",
"additionalProperties": false,
"properties": {
"button": {
"type": "string"
},
"text": {
"type": "string"
},
"border": {
"type": "string"
}
}
}
},
"allOf": [
{
"if": {
"properties": {
"key": {
"const": "customLink"
}
}
},
"then": {
"required": [
"color"
]
},
"else": {
"not": {
"required": [
"color"
]
}
}
}
]
}
}
}
}
}
}
]
}
}

How to use oneOf alongside a common sub-schema (V4)

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.