json schema definition using conditional statements - json

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

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

Items object should have equal property

I have a JSON like this:
{
"result": [
{
"name": "Adam",
"age": 22
},
{
"name": "John"
},
{
"name": "Justin",
"age": 25
}
]
}
and schema:
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/object1607582431.json",
"title": "Root",
"type": "object",
"required": [
"result"
],
"properties": {
"result": {
"$id": "#root/result",
"title": "Result",
"type": "array",
"default": [],
"items": {
"$id": "#root/result/items",
"title": "Items",
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"$id": "#root/result/items/name",
"title": "Name",
"type": "string",
"default": "",
"pattern": "^.*$"
},
"age": {
"$id": "#root/result/items/age",
"title": "Age",
"type": "integer",
"default": 0
}
}
}
}
}
}
Here age is an optional property. I am struggling to apply a rule if an optional property is present in one object then it should present in all the objects in that collection. Is there any option available for this?
This is actually a really good use case for the if/then construct that really can't be replicated by using a oneOf like a switch statement. (Well done.)
You're going to want to add the if/then construct to the results property subschema. If the if passes, then the then MUST also apply.
"result": {
...,
"if": {
"contains": { "required": [ "age" ] } // 1
},
"then": {
"items": { "required": [ "age" ] } // 2
}
}
If the the result object contains an item that has an age property,
Require all items to have an age property.
Edit
Full schema:
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/object1607582431.json",
"title": "Root",
"type": "object",
"required": [
"result"
],
"properties": {
"result": {
"$id": "#root/result",
"title": "Result",
"type": "array",
"default": [],
"if": { "contains": { "required": [ "age" ] } },
"then": { "items": { "required": [ "age" ] } },
"items": {
"$id": "#root/result/items",
"title": "Items",
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"$id": "#root/result/items/name",
"title": "Name",
"type": "string",
"default": "",
"pattern": "^.*$"
},
"age": {
"$id": "#root/result/items/age",
"title": "Age",
"type": "integer",
"default": 0
}
}
}
}
}
}
Instance:
{
"result": [
{
"name": "one"
},
{
"name": "two",
"age": 5
},
{
"name": "three"
}
]
}
Remove the age property or add it to the other items to get the schema to pass.

Json schema validation for property that can only be set once on an object inside an array

Is it possible to validate the json data below, so that "info" can only be filled in when "name" is "a" otherwise it must be empty or null?
[
{
"name": "a",
"info": "this is mandatory"
},
{
"name": "b",
"info": "validation must fail"
}
]
the JSONSchema
{
"title": "Array of things",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": [
"a",
"b"
]
},
"info": {
"type": "string"
}
}
}
}
The json in an online editor
try this:
{
"title": "Array of things",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"enum": ["a", "b"]
},
"info" : {
"type": ["string", "null"]
}
},
"required": ["name"],
"oneOf": [
{
"properties": {
"name": {"enum": ["a"] }
},
"required": ["info"]
},
{
"properties": {
"name": {"enum": ["b"] },
"info": {"enum": [null]}
}
}
]
}
}

How to reference json schema definition from another schema

I have a json schema representing a geometry as a Point or a MultiPoint. Each is defined within the schema in "definitions":
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://schema.my-site.org/geometry.json#",
"type": "object",
"oneOf": [
{
"allOf": [
{
"required": [
"type",
"coordinates"
]
},
{
"oneOf": [
{
"$ref": "#/definitions/Point"
},
{
"$ref": "#/definitions/MultiPoint"
}
]
}
]
}
],
"definitions": {
"Point": {
"title": "Point",
"type": "object",
"properties": {
"type": {
"enum": [
"Point"
]
},
"coordinates": {
"$ref": "#/definitions/position"
}
}
},
"MultiPoint": {
"title": "MultiPoint",
"type": "object",
"properties": {
"type": {
"enum": [
"MultiPoint"
]
},
"coordinates": {
"$ref": "#/definitions/positionArray"
}
}
},
"position": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"additionalItems": false,
"items": [
{
"type": "number"
},
{
"type": "number"
}
]
},
"positionArray": {
"type": "array",
"items": {
"$ref": "#/definitions/position"
}
}
}
}
Now I want to make another schema, which makes use of the Point definition. Currently, I copypasted the definitions for Point and position in the properties "startPosition" and "endPosition" and it works. But is there a way how to just reference the Point's definition from my geometry.json schema?
note: I only want to allow Point to be used here but not a MultiPoint - A geometry.json ref would allow both instead.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://schema.my-site.org/myitem.json#",
"type": "object",
"additionalProperties": false,
"required": [
"myproperty"
],
"properties": {
"myproperty": {
"type": "array",
"minItems": 0,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"startPosition": {
"geometry": {
"required": [
"type",
"coordinates"
],
"title": "Point",
"type": "object",
"properties": {
"type": {
"enum": [
"Point"
]
},
"coordinates": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"additionalItems": false,
"items": [
{
"type": "number"
},
{
"type": "number"
}
]
}
}
}
},
"endPosition": {
"geometry": {
"required": [
"type",
"coordinates"
],
"title": "Point",
"type": "object",
"properties": {
"type": {
"enum": [
"Point"
]
},
"coordinates": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"additionalItems": false,
"items": [
{
"type": "number"
},
{
"type": "number"
}
]
}
}
}
}
}
}
}
}
}
Haven't tested it myself, but according to this, you can make use of JSON pointers:
In file geometry.json:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://schema.my-site.org/geometry.json",
"type": "object",
"definitions": {
"Point": { ...},
"MultiPoint": {...}
}
}
In file myitem.json:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://schema.my-site.org/myitem.json#",
"type": "object",
"properties": {
"point": {
"$ref": "http://schema.my-site.org/geometry.json#definitions/Point"
}
}
}