How to validate a complex schema using meta-schema? - json

I'm trying to validate some schemas that I already have against to a meta-schema using the Ajv lib. I'm getting the result that the schemas are valid even when if I change it to an invalid definition.
This is one schema:
{
"id": "TEST_SCHEMA",
"name": "TEST_SCHEMA",
"type": "object",
"properties": {
"isEnabled": {
"type": "boolean",
"name": "isEnabled",
"default": false
},
"options": {
"type": "array",
"name": "options",
"items": {
"type": "object",
"properties": {
"content": {
"type": "string",
"name": "content",
"default": ""
},
"isChecked": {
"type": "boolean",
"name": "isChecked",
"default": true
},
"entities": {
"type": "array",
"name": "entities",
"uniqueItems": true,
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"club",
"businessPartners"
]
}
}
}
},
"channels": {
"type": "array",
"name": "channels",
"uniqueItems": true,
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"email",
"phone",
"sms",
"post"
]
}
}
}
}
}
}
}
}
}
This is my meta-schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://www.example.com/meta-schema.json#",
"title": "Core schema meta-schema",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#" }
},
"schemaObject": {
"type": "object",
"minProperties": 1,
"patternProperties": {
"^([A-Za-z0-9_$]){2,}$": {"$ref": "#"}
},
"additionalProperties": fanlse
},
"simpleTypes": {
"enum": [
"array",
"boolean",
"integer",
"null",
"number",
"object",
"string",
"function"
]
},
"stringArray": {
"type": "array",
"items": { "type": "string" },
"uniqueItems": true,
"default": []
}
},
"type": ["object", "boolean"],
"properties": {
"id": {
"type": "string",
"format": "uri-reference"
},
"$ref": {
"type": "string",
"format": "uri-reference"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": true,
"readOnly": {
"type": "boolean",
"default": false
},
"pattern": {
"type": "string",
"format": "regex"
},
"items": {
"$ref": "#",
"default": true
},
"uniqueItems": {
"type": "boolean",
"default": false
},
"required": { "$ref": "#/definitions/stringArray" },
"additionalProperties": { "$ref": "#" },
"definitions": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"properties": {
"$ref": "#",
"default": true
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/stringArray" }
]
}
},
"propertyNames": { "$ref": "#" },
"enum": {
"type": "array",
"items": true,
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{ "$ref": "#/definitions/simpleTypes" },
{
"type": "array",
"items": { "$ref": "#/definitions/simpleTypes" },
"minItems": 1,
"uniqueItems": true
}
]
}
},
"default": true
}
How I'm using Ajv:
const ajv = new Ajv({
allErrors: true,
schemaId: `auto`,
extendRefs: `fail`,
schemas: refs,
meta: META_SCHEMA
})
try {
ajv.validateSchema(schema)
} catch (error) {
console.error(`Schema Validation Error:`, file, error)
console.table(ajv.errors, [`keyword`,`params`,`message`])
}
I expect the schemas to fail when they have an invalid definition.
My meta-schema is wrong or am I using Ajv in wrong way?

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.

How to prevent additions properties when using oneOf in JSON Schema

I have a JSON configuration with an array of "specs", with many different kinds of "path" properties. The "kind" property is the selector of the variant.
I want to restrict the validation to not allow addition properties. In the JSON example, the properties "noAllowedInt" and "notAllowedObject" must report a validation error.
How can I add this rule to the JSON schema?
{
"specs": [
{
"id": 12,
"label": "Serial",
"path": {
"kind": "serial",
"speed": 9600,
"parity": "even"
}
},
{
"id": 13,
"label": "Memory",
"path": {
"kind": "memory",
"storage": "permanent",
"location": "external"
},
"noAllowedInt": 42,
"notAllowedObject": {
"value": 3.1415
}
}
]
}
There are two Json Schema to validate this, a simple one and one with "definitions"
Simple JSON Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"specs": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"properties": {
"id": {
"type": "integer"
},
"label": {
"type": "string"
}
},
"required": [
"id",
"label"
],
"oneOf": [
{
"type": "object",
"properties": {
"path": {
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"enum": [
"serial"
]
},
"speed": {
"type": "integer"
},
"parity": {
"type": "string"
}
},
"required": [
"kind"
]
}
}
},
{
"type": "object",
"properties": {
"path": {
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"enum": [
"memory"
]
},
"storage": {
"type": "string"
},
"location": {
"type": "string"
}
},
"required": [
"kind"
]
}
}
}
]
}
}
},
"required": [
"specs"
]
}
JSON Schema with "definitions"
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"specs": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"properties": {
"id": {
"type": "integer"
},
"label": {
"type": "string"
}
},
"required": [
"id",
"label"
],
"oneOf": [
{
"$ref": "#/definitions/PathKindSerialType"
},
{
"$ref": "#/definitions/PathKindMemory"
}
]
}
}
},
"required": [
"specs"
],
"definitions": {
"PathKindSerialType": {
"type": "object",
"additionalProperties": true,
"properties": {
"path": {
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"enum": [
"serial"
]
},
"speed": {
"type": "integer"
},
"parity": {
"type": "string"
}
},
"required": [
"kind"
]
}
}
},
"PathKindMemory": {
"type": "object",
"additionalProperties": true,
"properties": {
"path": {
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"enum": [
"memory"
]
},
"storage": {
"type": "string"
},
"location": {
"type": "string"
}
},
"required": [
"kind"
]
}
}
}
}
}
I guess you need to keep the path definition as a property at the specs array level. This would be my proposal:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "JSON schema generated with JSONBuddy https://www.json-buddy.com",
"type": "object",
"additionalProperties": false,
"properties": {
"specs": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "integer"
},
"label": {
"type": "string"
},
"path": {
"oneOf": [
{
"$ref": "#/definitions/PathKindSerialType"
},
{
"$ref": "#/definitions/PathKindMemory"
}
]
}
},
"required": [ "id", "label" ]
}
}
},
"required": [ "specs" ],
"definitions": {
"PathKindSerialType": {
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"enum": [ "serial" ]
},
"speed": {
"type": "integer"
},
"parity": {
"type": "string"
}
},
"required": [ "kind" ]
},
"PathKindMemory": {
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"enum": [ "memory" ]
},
"storage": {
"type": "string"
},
"location": {
"type": "string"
}
},
"required": [ "kind" ]
}
}
}

JSONSchema (draft 7) not validating child definitions for arrays

I'm getting very confused as to why my JSONSchema will not validate my data as expected.
I've appended my JSONShema and Example Date below.
The schema validates the first layer of the nested data structure (the Organisation) without issue, but fails to validate the second layer (User) and below.
Can anybody point me in the right direction as to what I'm doing wrong?
Much appreciated!
JSONSchema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://myorg/json/schemas/report-schedule.json",
"type": "array",
"items": {
"$ref": "#/definitions/Organisation"
},
"definitions": {
"Organisation": {
"type": "object",
"required": [
"organisationId",
"organisationName",
"users"
],
"properties": {
"organisationId": {
"type": "string",
"minLength": 1
},
"organisationName": {
"type": "string",
"minLength": 1
},
"users": {
"type": "array",
"items": {
"ref": "#/definitions/User"
}
}
}
},
"User": {
"type": "object",
"required": [
"name",
"email",
"reports"
],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"email": {
"type": "string",
"format": "email"
},
"reports": {
"type": "array",
"items": {
"ref": "#/definitions/Report"
}
}
}
},
"Report": {
"type": "object",
"required": [
"reportType",
"reportWeekEndDay",
"sendDay",
"sendHour",
"locations",
"widgets"
],
"properties": {
"reportType": {
"type": "string",
"enum": [
"org-weekly"
]
},
"reportWeekEndDay": {
"type": "integer",
"maximum": 6,
"minimum": 0
},
"sendDay": {
"type": "integer",
"maximum": 6,
"minimum": 0
},
"sendHour": {
"type": "integer",
"maximum": 23,
"minimum": 0
},
"locations": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"widgets": {
"$ref": "#/definitions/Widgets"
}
}
},
"Widgets": {
"type": "array",
"title": "Widgets within a report",
"items": {
"$ref": "#/definitions/Widget"
}
},
"Widget": {
"type": "object",
"required": [
"widgetType",
"metrics",
"comparisonType"
],
"properties": {
"widgetType": {
"type": "string",
"enum": [
"table-individual-locations",
"table-all-locations"
]
},
"comparisonType": {
"type": "string",
"enum": [
"week-on-week",
"3-and-1-month-weekly-avg"
]
},
"metrics": {
"$ref": "#/definitions/Metrics"
}
}
},
"Metrics": {
"type": "array",
"title": "The Available Metrics",
"items": {
"oneOf": [
{
"$ref": "#/definitions/FootFallAndMovement"
},
{
"$ref": "#/definitions/Engagement"
},
{
"$ref": "#/definitions/Occupancy"
},
{
"$ref": "#/definitions/SalesDataTransactions"
},
{
"$ref": "#/definitions/SalesDataConversion"
}
]
}
},
"FootFallAndMovement": {
"type": "object",
"required": [
"title",
"type",
"endpoint",
"queryParams"
],
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"const": "FootFallAndMovement"
},
"endpoint": {
"type": "string",
"minLength": 1
},
"queryParams": {
"type": "object",
"required": [
"excludeStaff"
],
"properties": {
"excludeStaff": {
"type": "boolean"
}
}
}
}
},
"Engagement": {
"type": "object",
"required": [
"title",
"type",
"endpoint",
"queryParams"
],
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"const": "Engagement"
},
"endpoint": {
"type": "string",
"minLength": 1
},
"queryParams": {
"type": "object",
"required": [
"excludeStaff",
"contexts"
],
"properties": {
"additionalFilters": {
"type": "object",
"required": [
"ignoreLingerUnder"
],
"properties": {
"ignoreLingerUnder": {
"type": "integer",
"minimum": 1
}
}
},
"excludeStaff": {
"type": "boolean"
},
"contexts": {
"type": "object",
"required": [
"type",
"value"
],
"properties": {
"type": {
"type": "string",
"const": "taxonomy"
},
"value": {
"type": "string",
"minLength": 1
}
}
}
}
}
}
},
"Occupancy": {
"type": "object",
"required": [
"title",
"type",
"endpoint",
"queryParams"
],
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"const": "Occupancy"
},
"endpoint": {
"type": "string",
"minLength": 1
},
"queryParams": {
"type": "object",
"required": [
"excludeStaff",
"contexts"
],
"properties": {
"excludeStaff": {
"type": "boolean"
},
"contexts": {
"type": "object",
"required": [
"type",
"value"
],
"properties": {
"type": {
"type": "string",
"const": "taxonomy"
},
"value": {
"type": "string",
"minLength": 1
}
}
}
}
}
}
},
"SalesDataTransactions": {
"type": "object",
"required": [
"title",
"type",
"endpoint"
],
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"const": "SalesDataTransactions"
},
"endpoint": {
"type": "string",
"minLength": 1
}
}
},
"SalesDataConversion": {
"type": "object",
"required": [
"title",
"type",
"endpoint",
"queryParams"
],
"properties": {
"title": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"const": "SalesDataConversion"
},
"endpoint": {
"type": "string",
"minLength": 1
},
"queryParams": {
"type": "object",
"required": [
"excludeStaff"
],
"properties": {
"excludeStaff": {
"type": "boolean"
}
}
}
}
}
}
}
Example Data
[
{
"organisationName": "a",
"organisationId": "a",
"users": [
{
"nameWITHERROR": "a"/*e.g. name should be required*/,
"email": "rob#test.com",
"reports": [
{
"reportType": "org-weekly1"/*e.g. this should be an enum*/,
"reportWeekEndDay": 6,
"sendDay": 6,
"sendHour": 6,
"locations": [
"abc",
"bcd"
],
"widgets": [
{
"widgetType": "table-all-locations",
"comparisonType": "3-and-1-month-weekly-avg",
"metrics": [
{
"title": "test",
"type": "FootFallAndMovement1"/*e.g. this enum should fail*/,
"endpoint": "/test",
"queryParams": {
"excludeStaff": true
}
},
{
"title": "test",
"type": "Engagement",
"endpoint": "/test",
"queryParams": {
"excludeStaff": true,
"contexts": {
"type": "taxonomy",
"value": "tests"
}
}
},
{
"title": "test",
"type": "Occupancy",
"endpoint": "/test",
"queryParams": {
"excludeStaff": true,
"contexts": {
"type": "taxonomy",
"value": "tests"
}
}
},
{
"title": "test",
"type": "SalesDataTransactions",
"endpoint": "/test"
},
{
"title": "test",
"type": "SalesDataConversion",
"endpoint": "/test",
"queryParams": {
"excludeStaff": true
}
}
]
}
]
}
]
}
]
}
]
Opening your JSON schema in JSONBuddy shows me immediately that you have used "ref" at /definitions/Organisation/properties/users/items/ref. So there is no validation because the definition is not found.

json schema definition using conditional statements

Iam trying to define an optional condition using json schema conditional statement (Using draft 7)
I have a json response like this.
[{
"views": [{
"name": "RSO Roster",
"displayOrder": 5,
"groups": [{
"type": "scrollable",
"displayOrder": 1,
"auditType": "player-pregame_roster",
"tiles": [{
"context": "event",
"dataStamp": 1535184247,
"tile_type": "person"
}, {
"context": "event",
"errorCode": 2,
"errorText": "seloger",
"tile_type": "person"
}
]
}
]
},
{
"name": "Leaders",
"displayOrder": 1,
"groups": [{
"type": "static",
"displayOrder": 1,
"tiles": [{
"context": "event",
"dataStamp": 1535184247,
"eventId":123
"tile_type": "static"
}
]
}
]
}
]
}]
In this response if the tile object contains the key errorCode the required field must be errorText and errorCode keys.Like wise
if the tile object doessnot contains any "errorCode" or "errorText" key then the tile item contains the required field "dataStamp".
To validate the above condition i have defined a schema like below.But it is not working.Whats wrong with my schema .
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"type": "object",
"properties": {
"views": {
"$id": "views",
"type": "array",
"items": {
"$id": "views/items",
"type": "object",
"properties": {
"groups": {
"$id": "views/groups",
"type": "array",
"items": {
"$id": "views/groups/items",
"type": "object",
"properties": {
"tiles": {
"$id": "views/groups/tiles",
"type": "array",
"items": {
"$id": "views/groups/tiles/items",
"type": "object",
"properties": {
"dataStamp": {
"$id": "views/groups/tiles/dataStamp",
"type": "integer"
},
"tile_type": {
"$id": "views/groups/tiles/tile_type",
"type": "string"
},
"errorCode": {
"type": "integer",
"enum": [
2, 10
]
},
"errorText": {
"type": "string",
"enum": [
"seloger", "france24"
]
}
},
"if": {
"properties": {
"tile_type": {
"enum": ["person"]
},
"errorCode": {
"enum": [2, 10]
}
},
"required": ["errorCode", "errorText"]
}
}
}
},
"required": [
"type",
"tiles"
]
}
}
},
"required": [
"groups"
]
}
}
},
"required": [
"views"
]
}
}
The if statement is missing required in properties:
"if": {
"properties": {
"tile_type": {
"enum": ["person"]
},
"errorCode": {
"enum": [2, 10]
},
"required": ["errorCode"]
}
},
If there is no required the value of property is validated only if the property is set. So original if schema would pass any object without tile_type and errorCode.
https://stackoverflow.com/a/51034071/329463 might give you some inspiration on building exclusive properties clusters.
EDIT: modified full schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"type": "object",
"properties": {
"views": {
"$id": "views",
"type": "array",
"items": {
"$id": "views/items",
"type": "object",
"properties": {
"groups": {
"$id": "views/groups",
"type": "array",
"items": {
"$id": "views/groups/items",
"type": "object",
"properties": {
"tiles": {
"$id": "views/groups/tiles",
"type": "array",
"items": {
"$id": "views/groups/tiles/items",
"type": "object",
"properties": {
"dataStamp": {
"$id": "views/groups/tiles/dataStamp",
"type": "integer"
},
"tile_type": {
"$id": "views/groups/tiles/tile_type",
"type": "string"
},
"errorCode": {
"type": "integer",
"enum": [
2, 10
]
},
"errorText": {
"type": "string",
"enum": [
"seloger", "france24"
]
}
},
"if": {
"properties": {
"tile_type": {
"enum": ["person"]
},
"errorCode": {
"enum": [2, 10]
}
},
"required":["errorCode"]
},
"then": {
"required": ["errorCode", "errorText"]
},
"else": {
"required": ["dataStamp"]
}
}
}
},
"required": [
"type",
"tiles"
]
}
}
},
"required": [
"groups"
]
}
}
},
"required": [
"views"
]
}
}

JsonSchema: Validate type based on value of another property

I am using the following schema to validate my json:
{
"$schema": "http://json-schema.org/schema#",
"title": " Rules",
"description": "Describes a set of rules",
"type": "object",
"properties": {
"rules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"precedence": {
"type": "number",
"minimum": 0
},
"conditions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"field": {
"type": "string",
"enum": [ "Name", "Size" ]
},
"relation": {
"type": "string",
"enum": [ "is", "is not", "is not one of", "is one of" ]
},
"value": {
"type": ["array", "string", "number"]
}
},
"required": ["field", "relation", "value"],
"additionalProperties": false
}
}
},
"required": ["precedence", "conditions"],
"additionalProperties": false
}
}
},
"required": ["rules"],
"additionalProperties": false
}
I want to set up a dependency to validate that when the value of the relation property has the value is one of or the value is not one of, then the type of the value property can only be array
For example, the following json should not validate because it uses the relation value is not one of and the value property is not an array:
{
"rules": [{
"precedence": 0,
"conditions": [{
"field": "Name",
"relation": "is not one of",
"value": "Mary"
}
]
}
]
}
Is it possible to set up dependencies to validate this way?
The best way to solve these kinds of problems is to separate the complex validation from the rest of the schema using definitions and include it with an allOf. In this solution, I use implication to enforce the validation.
{
"type": "object",
"properties": {
"rules": {
"type": "array",
"items": { "$ref": "#/definitions/rule" }
}
},
"required": ["rules"],
"definitions": {
"rule": {
"type": "object",
"properties": {
"precedence": { "type": "number", "minimum": 0 },
"conditions": {
"type": "array",
"items": { "$ref": "#/definitions/condition" }
}
},
"required": ["precedence", "conditions"]
},
"condition": {
"type": "object",
"properties": {
"field": { "enum": ["Name", "Size"] },
"relation": { "enum": ["is", "is not", "is not one of", "is one of"] },
"value": { "type": ["array", "string", "number"] }
},
"required": ["field", "relation", "value"],
"allOf": [{ "$ref": "#/definitions/array-condition-implies-value-is-array" }]
},
"array-condition-implies-value-is-array": {
"anyOf": [
{ "not": { "$ref": "#/definitions/is-array-condition" } },
{ "$ref": "#/definitions/value-is-array" }
]
}
"is-array-condition": {
"properties": {
"relation": { "enum": ["is not one of", "is one of"] }
},
"required": ["relation"]
},
"value-is-array": {
"properties": {
"value": { "type": "array" }
}
}
}
}
If you are able to use the latest draft-7 version of JSON Schema, you can use if then else, as per https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-00#section-6.6
Although, using oneOf is also a valid approach, it might not be as clear to someone else inspecting your schema at a later date.
I've copied an example from an answer to another question:
If the "foo" property equals "bar", Then the "bar" property is
required
{
"type": "object",
"properties": {
"foo": { "type": "string" },
"bar": { "type": "string" }
},
"if": {
"properties": {
"foo": { "enum": ["bar"] }
}
},
"then": { "required": ["bar"] }
}
(You may want to check the draft support of the library you are using.)
There may be a more concise way to do this, but this will work:
{
"$schema": "http://json-schema.org/schema#",
"title": "Rules",
"description": "Describes a set of rules",
"definitions": {
"field": {
"type": "string",
"enum": ["Name", "Size"]
}
},
"type": "object",
"properties": {
"rules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"precedence": {
"type": "number",
"minimum": 0
},
"conditions": {
"type": "array",
"items": {
"type": "object",
"oneOf": [
{
"properties": {
"field": {
"$ref": "#/definitions/field"
},
"relation": {
"type": "string",
"enum": ["is", "is not"]
},
"value": {
"type": ["string", "number"]
}
},
"required": ["field", "relation", "value"],
"additionalProperties": false
},
{
"properties": {
"field": {
"$ref": "#/definitions/field"
},
"relation": {
"type": "string",
"enum": ["is not one of", "is one of"]
},
"value": {
"type": ["array"]
}
},
"required": ["field", "relation", "value"],
"additionalProperties": false
}
]
}
}
},
"required": ["precedence", "conditions"],
"additionalProperties": false
}
}
},
"required": ["rules"],
"additionalProperties": false
}