A common JSON Schema for similar structure - json

I'm completely new to json and json schema, so I have a question (yet I don't know how much it make sense). Can we create a json schema which is common for similar type of structure. For example:
One single schema can be used to validate following json
JSON:
{
"Team_Table":
[{"Name":"New Zealand", "Match":"Six", "Won":"Six"}]
}
And
{
"Story_Taller":
[{"Story":"No Name", "Chapter":"Don't know"}]
}
Similarities:
Both have only one object in the array
Objects have string value.
Dissimilarities:
Number of properties are different
Keys are different in both
Can we do this?

Maybe this helps you along:
{
"properties": {
"Story_Taller": {
"type": "array",
"maxItems": 1,
"items": {
"properties": {
"Chapter": {
"type": "string"
},
"Story": {
"type": "string"
}
},
"additionalProperties": false
}
},
"Team_Table": {
"type": "array",
"maxItems": 1,
"items": {
"properties": {
"Name": {
"type": "string"
},
"Match": {
"type": "string"
},
"Won": {
"type": "string"
}
},
"additionalProperties": false
}
}
},
"oneOf": [
{
"title": "Story_Taller",
"required": [
"Story_Taller"
]
},
{
"title": "Team_Table",
"required": [
"Team_Table"
]
}
]
}
in (short) words:
in your JSON there must be one property of either "Story_Taller" or "Team_Table" with a maximum of 1 item
"oneOf": [ ... ]
Properties of both arrays are defined by items
"Story_Taller" must have "Chapter" and "Story" and no additional properties.
"Team_Table" must have "Name", "Match", "Won" and no additional properties.
And all of them are defined as strings.

Related

How do I inform a Json schema that it must have atleast one type of object in its Array, but other types are optional

I am working on updating a JSON schema for work.
For the json array, we have
"accountsInfo": [{
"type":"ADMIN",
"firstName":"Bill",
"lastName":"Cipher",
"emailAddress":"bcipher#gfalls.com"
}, {
"type":"USER"
"firstName":"Bugs",
"lastName":"Bunny",
"emailAddress":"whats#updoc.org"
}]
The USER type is needs to be optional for this schema, with the atleast 1 ADMIN type is required in the array. How can I do this?
Here is the portion of the schema file. It is using Json Schema 7.
"accountsInfo": {
"type": "array",
"uniqueItems": true,
"minItems": 2,
"items": [
{
"type": "object",
"required": [
"type",
"firstName",
"lastName",
"emailAddress"
],
"properties": {
"type": {
"type": "string",
"enum": [
"ADMIN",
"USER"
]
},
"firstName": {
"type": "string",
"$ref": "#/definitions/non-empty-string"
},
"lastName": {
"type": "string",
"$ref": "#/definitions/non-empty-string"
},
"emailAddress": {
"type": "string",
"format": "email"
}
}
}
]
}
You can use the "contains" keyword for this. In pseudocode: "the array must contain (at least one) item that successfully evaluates against this schema".
As a sibling keyword to "type": "object" and "items": { ... }, add:
"contains": {
"properties": {
"type": {
"const": "ADMIN"
}
}
}
Also, you have an error in your "items" keyword: if you intend for that subschema to match all items, not just the first, remove the extra array around the schema. The array form of "items" matches each item in the data against each item in the schema in turn, and you only specify a schema for the first item, so all items after the first can be anything.
"items": { .. schema .. } not "items": [ { .. schema .. } ].
If using the contains keyword as suggested, and if you are using strict mode, you may need to add "type": "array" like this:
{
"type": "array",
"contains": {
"properties": {
"type": {
"const": "ADMIN"
}
}
}
}

JSON Schema validating JSON with different property names

I am working with JSON Schema Draft 4 and am experiencing an issue I can't quite get my head around. Within the schema below you'll see an array, metricsGroups where any item should equal exactly oneOf the defined sub-schemas. Within the sub-schemas you'll notice that they both share the property name timestamp, but metricsGroupOne has the properties temperature and humidity whilst metricsGroupTwo has properties PIR and CO2. All properties within both metricsGroups are required.
Please see the schema below. Below the schema is an example of some data that I'd expect to be validated, but instead is deemed invalid and an explanation of my issue.
{
"type": "object",
"properties": {
"uniqueId": {
"type": "string"
},
"metricsGroups": {
"type": "array",
"minItems": 1,
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"metricsGroupOne": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"timestamp": {
"type": "string",
"format": "date-time"
},
"temperature": {
"type": "number"
},
"humidity": {
"type": "array",
"items": {
"type": "number"
}
}
},
"additionalProperties": false,
"required": [
"timestamp",
"temperature",
"humidity"
]
}
}
},
"required": [
"metricsGroupOne"
]
},
{
"type": "object",
"properties": {
"metricsGroupTwo": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"timestamp": {
"type": "string",
"format": "date-time"
},
"PIR": {
"type": "array",
"items": {
"type": "number"
}
},
"CO2": {
"type": "number"
}
},
"additionalProperties": false,
"required": [
"timestamp",
"PIR",
"CO2"
]
}
}
},
"required": [
"metricsGroupTwo"
]
}
]
}
}
},
"additionalProperties": false,
"required": [
"uniqueId",
"metricsGroups"
]
}
Here's some data that I believe should be valid:
{
"uniqueId": "d3-52-f8-a1-89-ee",
"metricsGroups": [
{
"metricsGroupOne": [
{"timestamp": "2020-03-04T12:34:00Z", "temperature": 32.5, "humidity": [45.0] }
],
"metricsGroupTwo": [
{"timestamp": "2020-03-04T12:34:00Z", "PIR": [16, 20, 7], "CO2": 653.76 }
]
}
]
}
The issue I am facing is that both of the metricsGroup arrays in my believed to be valid data validate against both of the sub-schemas - this then invalidates the data due to the use of the oneOf keyword. I don't understand how the entry for metricsGroupOne validates against the schema for metricsGroupTwo as the property names differ and vice versa.
I'm using an node library under the hood that throws this error, but I've also tested that the same error occurs on some online validation testing websites:
jsonschemavalidator
json-schema-validator
Any help is appreciated. Thanks,
Adam
JSON Schema uses a constraints based approach. If you don't define something is not allowed, it is allowed.
What's happening here is, you haven't specificed in oneOf[1] anything which would make the first item in your instance data array invalid.
Lete me illistrate this with a simple example.
My schema. I'm going to use draft-07, but there's no difference in this principal for draft-04
{
"oneOf": [
{
"properties": {
"a": true
}
},
{
"properties": {
"b": false
}
}
]
}
And my instance:
{
"a": 1
}
This fails validation because the instance is valid when both oneOf schemas are applied.
Demo: https://jsonschema.dev/s/EfUc4
If the instance was in stead...
{
"a": 1,
"b": 1
}
This would be valid, because the instance is fails validation for the subschema oneOf[1].
If the instance was...
{
"b": 1
}
It would be valid according to oneOf[0] but not according to oneOf[1], and therefore overall would be valid because it is only valid according to one subschema.
In your case, you probably need to use additionalProperties to make properties you haven't defined in properties dissallowed. I can't tell from your question if you want to allow both properties, because your schema is defined as oneOf which seems to conflict with the instance you expect to be valid.

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

JSON schema validation with Map of string with Enum constraints

Requesting help with JSON Schema validation, below is sample JSON and Schema. I am trying to figure out how to specify "ppd" schema rule specifically "cfg" is a map of String, String and need to further restrict the entries of the key and value in this map by Enum definition i.e. allowed values for "inputDateTimeFormat" is a valid date time format so rule should encode if key is "inputDateTimeFormat" then allowed value is a pattern matching date time format and similarly if key is "valuemapping" then allowed values is pattern matching k=v (example below).
Could you please suggest a way to achieve this?
JSON Sample -
{
"sm": [
{
"mid": "id-1",
"ppd": [
{
"name": "cc-1",
"cfg": {
"columns": "v-1",
"valueMapping": "B=01;S=02"
}
},
{
"name": "cc-2",
"cfg": {
"columns": "v-2",
"inputDateTimeFormat": "ddMMMyyyy_HH:mm:ss.SSSSSS",
"outputDateTimeFormat": "yyyy-MM-dd'T'HH:mm:Ss.SSSZ"
}
},
{
"name": "cc-3",
"cfg": {
"columns": "v-3;v-4",
"markers": "d=01"
}
}
]
}
]
}
JSON Schema :
{
"type": "object",
"$schema": "http://json-schema.org/draft-06/schema",
"id": "source-mappings-schema",
"required": true,
"properties": {
"sm": {
"type": "array",
"id": "source-mappings-schema/sm",
"required": true,
"items": {
"type": "object",
"id": "source-mappings-schema/sm/0",
"required": true,
"properties": {
"mappingId": {
"type": "string",
"id": "source-mappings-schema/sm/0/mappingId",
"required": true
},
"ppd": {
"type": "array",
"id": "source-mappings-schema/sm/0/ppd",
"required": true,
"items": {
"type": "object",
"id": "source-mappings-schema/sm/0/ppd/0",
"required": true,
"properties": {
"name": {
"type": "string",
"id": "source-mappings-schema/sm/0/ppd/0/name",
"required": true
},
"cfg": {
"type": "array",
"id": "source-mappings-schema/sm/0/ppd/0/cfg",
"required": true,
"items": {
"type": "string"
}
}
}
}
}
}
}
}
}
}
To start with your schema contains a few issue.
The $schema tag is wrong, it should be
"$schema": "http://json-schema.org/draft-06/schema#",
The 'required' property is supposed to be an array of property names that are required (not a bool), so you need to apply this at the level above.
Finally the validation of cfg. By specifying a schema for 'additionalProperties' you can provide validation rules for all unspecified key values (you said it was a map of strings, so I've set it to string, but you could also add other rules here like max length etc).
For the keys you know about you can add a property for each of them with the approrate validation rules (the rules i've added demonstrate the concept and will need tweaking for your use).
"cfg": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"properties": {
"inputDateTimeFormat": {
"type": "string",
"format": "date-time"
},
"valuemapping": {
"type": "string",
"pattern": "[a-z]\\=[a-z]"
}
}
}

How to describe this validation requirement in jsonschema?

I want to validate my API json response like this:
{
"code": 0,
"results": [
{"type":1, "abc": 123},
{"type":2, "def": 456}
]
}
I want to validate the objects within results to have a "abc" field when its type is 1, and "def" field when its type is 2. The results may contain arbitrary number of type1 and type2 objects.
Can I specify this in jsonschema? Or must I use a generic validator for elements in results and do validation myself?
You can do this using the anyOf keyword.
An instance validates successfully against this keyword if it validates successfully against at least one schema defined by this keyword's value.
http://json-schema.org/latest/json-schema-validation.html#anchor85
You need to define both types of items and then use anyOf To describe the array items for "results".
{
"type": "object",
"properties": {
"code": { "type": "integer" },
"results": {
"type": "array",
"items": { "$ref": "#/definitions/resultItems" }
}
},
"definitions": {
"resultItems": {
"type": "object",
"anyOf": [
{ "$ref": "#/definitions/type1" },
{ "$ref": "#/definitions/type2" }
]
},
"type1": {
"properties": {
"type": { "enum": [1] },
"abc": { "type": "integer" }
},
"required": ["abc"]
},
"type2": {
"properties": {
"type": { "enum": [2] },
"def": { "type": "integer" }
},
"required": ["def"]
}
}
}