Json schema not validating required attribute - json

i'm coding the following Json Schema:
{
"$schema": "http://json-schema.org/schema#",
"title": "Layout",
"description": "The layout created by the user",
"type": "object",
"definitions": {
"stdAttribute": {
"type": "object",
"properties": {
"attributeValue": {
"type": "object"
},
"attributeName": {
"type": "string"
}
}
},
"stdItem": {
"type": "object",
"required" : ["stdAttributes"],
"properties": {
"stdType": {
"enum": [
"CONTAINER",
"TEXT",
"TEXTAREA",
"BUTTON",
"LABEL",
"IMAGE",
"MARCIMAGE",
"DATA",
"SELECT",
"TABLE"
]
},
"stdAttributes": {
"type": "array",
"items": {
"$ref": "#/definitions/stdAttribute"
},
"minItems": 1
},
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/stdItem"
}
}
}
}
}
}
When i set the following data:
{
"stdItem": {
"stdType": "CONTAINER",
"stdAttributes": [],
"children": []
}
}
the validator says there is no error but in the schema i'm using a minItems and a ref to the "StdAttribute" schema in "StdAttributtes".
I tried to define this property in the base schema but the validator says the same thing.
How should i validate the type and number of items in "StdAttributes"?
I'm using the Java Validator.

You are missing a properties attribute at the top level. Right now the only thing your schema is validating is that your data is an object. definitions doesn't validate anything by itself. It's just a place to hold schemas that can be referenced in your schema. The following would be the minimum you would have to add to the root of your schema to get the results you expect.
"properties": {
"stdItem": { "$ref": "#/definitions/stdItem" }
}

Related

Conditional References in a JSON Schema

I want to write a single file JSON schema definition with several sub schemas that I can combine, depending on the payload.
The following schema validates, that my schema is working with my sample JSON response. (The response object has a wrong type for payload.role to make sure the schema catches this mistake!)
For clarity, I reduce it on the most important parts. A full working example can be found here: https://www.jsonschemavalidator.net/s/3KAaXjtg
Schema
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://example.com/baseSchema.json",
"type": "object",
"required": [
"payload"
],
"properties": {
"payload": {
"$id": "#/properties/payload",
"type": "object",
// reference the right schema depending on the payload child key
// if `payload.user` reference `userSchema.json`
// if `payload.users` reference `usersSchema.json`
// if `payload.*` reference `*Schema.json`
"$ref": "userSchema.json"
}
},
"definitions": {
"user": {
"$id": "http://example.com/userSchema.json",
"type": "object",
"required": [
"user"
],
"properties": {
"user": {
"type": "object",
"$ref": "userProperties.json"
}
}
},
"users": {
"$id": "http://example.com/usersSchema.json",
"type": "object",
"required": [
"users"
],
"properties": {
"users": {
"type": "array",
"items": {
"$ref": "userProperties.json"
}
}
}
},
"userProperties": {
"$id": "http://example.com/userProperties.json",
"type": "object",
"properties": {
"firstName": {
"$id": "#/properties/payload/properties/user/properties/firstName",
"type": "string"
}
}
}
}
}
Response
{
"status": {
"code": 200,
"description": "User retrieved successfully."
},
"payload": {
"user": {
"firstName": "Joe",
"lastName": "Doe",
"role": "3", // for testing reasons, this is the wrong type!
"email": "doe#example.com",
"customerID": "",
"projects": [
"AIXG5mEg6QLl9rhVSE6m",
"Bs1bHiOIqKclwwis3CNf",
"NC2OUGVZXU35FA7iwRn4"
],
"status": "Status",
"id": "c555BSZnKLdHSRYqrU5hqiQo733j13"
}
}
}
So I've got a baseSchema.json that matches this response:
{
"status": {},
"payload": {}
}
payload gets extended by a certain key like payload.user = {} or payload.foo = {} and depending on that key, I want to extend schema with one of my definitions.
The following part only works for the key user:
"properties": {
"payload": {
"$id": "#/properties/payload",
"type": "object",
// reference the right schema depending on the payload child key
// if `payload.user` reference `userSchema.json`
// if `payload.users` reference `usersSchema.json`
// if `payload.*` reference `*Schema.json`
"$ref": "userSchema.json"
}
},
I failed to setup any conditions (with allOf, if, else), that would reference the correct sub-schema, based on the payload key.
Any hints and help to solve that is appreciated.
Schema and link to demo at the end... Let's look at how we got there...
In JSON Schema draft-07 and previous, you can't use $ref alongside other keywords. Other keywords are ignored. (In your schema http://example.com/userSchema.json you had type next to $ref). Fortunatly this didn't cause you any problems as you declare the type in the referenced schema. (You CAN do this with 2019-09 or above.)
The values for the keywords if, then, and else are schemas.
For the then subschema to be applied to your instance location, the if schema must come back as valid. If it fails, the else subschema value will be applied.
Our if condition checks for the presense of a specific key.
If the key exists, THEN apply the schema which references the correct schema.
Because you want the conditions to be mutually exclusive, you need to wrap the multiple conditions in a oneOf, and add else: false to the conditional checks. false as a schema makes validation fail.
Let me know if you want any further clarification on any of the above.
Demo: https://jsonschema.dev/s/HLniL
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://example.com/baseSchema.json",
"type": "object",
"required": [
"payload"
],
"properties": {
"payload": {
"$id": "#/properties/payload",
"type": "object",
"oneOf": [
{
"if": {
"required": [
"user"
]
},
"then": {
"$ref": "userSchema.json"
},
"else": false
},
{
"if": {
"required": [
"users"
]
},
"then": {
"$ref": "usersSchema.json"
},
"else": false
}
]
}
},
"definitions": {
"user": {
"$id": "http://example.com/userSchema.json",
"type": "object",
"required": [
"user"
],
"properties": {
"user": {
"$ref": "userProperties.json"
}
}
},
"users": {
"$id": "http://example.com/usersSchema.json",
"type": "object",
"required": [
"users"
],
"properties": {
"users": {
"type": "array",
"items": {
"$ref": "userProperties.json"
}
}
}
},
"userProperties": {
"$id": "http://example.com/userProperties.json",
"type": "object",
"properties": {
"firstName": {
"type": "string"
}
}
}
}
}

JsonSchema - Only allow one item in an array field if another array field is defined

I have the following json and would like to only allow "leads" to contain only a single "id" item if there is a "tokens" array present (with at least one item).
JSON
{
"input": {
"leads": [
{
"id": 795333333760
}
],
"tokens": [
{
"name": "tem_x",
"value": "Renew_all"
},
{
"duration": "90",
"eligibility": "eligible"
}
]
}
I have the following schema, that indicates "tokens" can have more than one item if present and that "leads" is required.
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"input": {
"type": "object",
"properties": {
"leads": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"id": {
"type": "integer"
}
},
"required": [
"id"
]
}
]
},
"tokens": {
"type": "array",
"minItems": 1
}
},
"required": [
"leads",
]
}
},
"required": [
"input"
]
}
Is there a way to ensure that only one item in "leads" can be allowed if "tokens" is present (as it is not defined as a required field). If "tokens" is not defined, then I would like to allow the "leads" array to have more than one item.
I played around with if-then but wasn't able to get it working right. Any help is appreciated.
Thank you.
This is the kind of thing the dependencies keyword is for. It can be done with if/then or implication as well, but dependencies removes all the extra boilerplate needed for those patterns. The following says, if the "tokens" property is defined, then the "leads" property must have at most 1 item. This would go inside your "input" schema.
"dependencies": {
"tokens": {
"properties": {
"leads": { "maxItems": 1 }
}
}
}
Edit: dependencies works in draft-04 thru draft-07. In draft 2019-09 and up, you can use dependentSchemas instead.
try to use like this:
{
"properties": {
"tokens": {},
"leads": {}
},
"anyOf": [{
"required" : ["tokens"]
}, {
"required" : ["leads"]
}]
}
so schema looks like this:
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"input": {
"type": "object",
"properties": {
"leads": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"id": {
"type": "integer"
}
},
"required": [
"id"
]
}
]
},
"tokens": {
"type": "array",
"minItems": 1
}
},
"anyOf": [{
"required" : ["tokens"]
}, {
"required" : ["leads"]
}]
}
},
"required": [
"input"
]
}

Json Schema Dependencies with Object Definitions

When using json schema 7 is it possible to set a dependency on an object definition references rather individual fields?
For example I have a type string and properties object. Depending on the type the properties object fields will be different but I don't want to set dependancy of every possible field. That's rather tedious e.g.
{
"$id": "https://sibytes.datagovernor.com/dataset.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "dataset",
"type": "object",
"properties": {
"dataset_type": {
"type": "string",
"description": ""
},
"dataset_properties": {
<< BASICALLY HERE I WANT THE REFERENCE OBJECT DEFINITION TO BE DEPENDENT ON THE DATASET TYPE ABOVE>>
"$ref": "http://example.com/tableproperties.schema.json"
"$ref": "http://example.com/tableproperties.fileproperties.json"
...there will be others.
}
}
}
So turns out this can de done using sub-schema's and predicates
https://json-schema.org/understanding-json-schema/reference/conditionals.html
{
"$id": "https://sibytes.datagovernor.com/dataset.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "dataset",
"type": "object",
"properties": {
"dataset_type": {
"enum": ["Table","View"],
"description": "This is the type of physical object that the dataset describes."
}
},
"dataset_properties": {
"allOf": [
{
"if": {
"properties": {"dataset_type":{"const": "Table"}}
},
"then": {
"properties": {
"dataset_properties" : {
"$ref": "dataset.table.schema.json#/definitions/dataset_properties"
}
}
}
},
{
"if": {
"properties": {"dataset_type":{"const": "View"}}
},
"then": {
"properties": {
"dataset_properties" : {
"$ref": "dataset.view.schema.json#/definitions/dataset_properties"
}
}
}
}
]
},
"required": ["dataset_type","dataset_properties"]
}

JSON Schema for child objects with different set of keys

I have JSON data of which is an array of data like
[
{
"type": "background_color",
"data": {
"backgroundColor": "F9192D"
}
},
{
"type": "banner_images",
"data": {
"images": [
{
"url": "https://example.com/abc.jpg",
"id": 3085
},
{
"url": "https://example.com/zyx.jpg",
"id": 3086
}
]
}
},
{
"type": "description_box",
"data": {
"text": "Hello 56787"
}
}
]
The data is an array of object which has two keys type and data. The type and keys of the data will be defined by the type of data it has.
Like for background_color type, the data should have backgroundColor property, while for banner_images, data should have images which is an array of other properties.
Till now, What I have done is
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"title": "category schema",
"description": "Used to validate data of category",
"examples": [],
"required": [],
"items": {
"type": "object",
"required": [
"type",
"data"
],
"properties": {
"type": {
"type": "string",
"enum": ["background_color", "banner_images", "description_box"]
},
"data": {
"type": "object" // How to define data property here for each use case
}
}
}
}
I'm not getting how to define the data property for each use case?
You can use if/then/else blocks to define conditional constraints.
The values of if and then are schemas. If the if schema is valid, then the then schema is applied, otherwise, the allOf subschema (allOf[0] in this example) would pass validation.
There are a few different ways to do this, but this is clean when you don't have any additional or special requirements. Please come back if you do =]
In this example, I've added banner_images...
You can test it working here.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"title": "category schema",
"description": "Used to validate data of category",
"items": {
"type": "object",
"required": [
"type",
"data"
],
"properties": {
"type": {
"type": "string",
"enum": [
"background_color",
"banner_images",
"description_box"
]
},
"data": {
"type": "object"
}
},
"allOf": [
{
"if": {
"properties": {
"type": {
"const": "banner_images"
}
}
},
"then": {
"properties": {
"data": {
"required": [
"images"
],
"properties": {
"images": {
"type": "array"
}
}
}
}
}
}
]
}
}
For reference, here's the part of the JSON Schema draft-7 spec document that details the behaviour: https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.6

Json schema for recursive structure not working

Here is my json schema. I want a recursive tree-like structure. But the response is passing even when I have invalid objects in the required array.
{
"$schema":"http://json-schema.org/draft-03/schema",
"properties":{
"Result":{
"type":"object",
"properties":{
"Children":{
"$ref":"#/definitions/Node"
}
},
"required":true
}
},
"required":true,
"type":"object",
"definitions":{
"Node":{
"type":"array",
"Items":{
"type":"object",
"properties":{
"Children":{
"$ref":"#/definitions/Node"
}
},
"required":true
}
}
}
}
To check that the JSON Schema validation will validate correctly , I deliberately put an invalid object inside the response -
{"Result":{"title":"title","Children":[{"invalidobject":"invalidobject"}]}}
But it is passing here - https://www.jsonschemavalidator.net/
What I actually want is Children to also have an array of Children and so on. So, only Children having objects with properties - title and Children should be allowed.
Its passing for this response too -
{"Result":{"title":"title","Children":[{"title":45}]}}
Try this schema. Note that this schema will allow children array to be empty even on the first level. After the first level, you have to allow children array to be empty otherwise, the schema will expect infinitely recursive data in order to pass validation.
{
"$schema": "http://json-schema.org/draft-03/schema",
"type": "object",
"properties": {
"Result": {
"$ref": "#/definitions/node",
"required":true,
}
},
"definitions": {
"node": {
"type": "object",
"properties": {
"title": {
"type": "string",
"required": true
},
"Children": {
"type": "array",
"required": true,
"items": {
"$ref": "#/definitions/node"
}
}
},
"additionalProperties": false
}
}
}
In case you do not want to allow children array to be empty at first level try defining the first level separately like this.
{
"$schema": "http://json-schema.org/draft-03/schema",
"type": "object",
"properties": {
"Result": {
"type": "object",
"required": true,
"properties": {
"title": {
"$ref": "#/definitions/title"
},
"Children": {
"minItems": 1,
"$ref": "#/definitions/Children"
}
},
"additionalProperties": false
}
},
"definitions": {
"title": {
"type": "string",
"required": true
},
"Children": {
"type": "array",
"required": true,
"items": {
"$ref": "#/definitions/node"
}
},
"node": {
"type": "object",
"properties": {
"title": {
"$ref": "#/definitions/title"
},
"Children": {
"$ref": "#/definitions/Children"
}
},
"additionalProperties": false
}
}
}
Here the validation results for sample input JSONs validated from https://www.jsonschemavalidator.net/
Input JSON:
{
"Result": {
"title": "title",
"Children": [
{
"invalidobject": "invalidobject"
}
]
}
}
Validation result:
Message:
Property 'invalidobject' has not been defined and the schema does not allow additional properties.
Schema path:
#/definitions/node/additionalProperties
Message:
Required properties are missing from object: title, Children.
Schema path:
#/definitions/node/required
Inpot JSON:
{
"Result": {
"title": "title",
"Children": [
{
"title": 45
}
]
}
}
Validation result:
Message:
Invalid type. Expected String but got Integer.
Schema path:
#/definitions/node/properties/title/type
Message:
Required properties are missing from object: Children.
Schema path:
#/definitions/node/required