I’m creating a schema consists of multiple categories. In each category there’s an array of key:value pairs. Each key represents the display name of value. Each value is unique and can only be assigned to a single key and category.
As an example, a category called ‘primates’ will have ‘human’ as one of the key/ display name, and the biological name ‘Homo sapiens’ will be the corresponding value of the key:value pair.
I want to validate data entry so that data matches with only one of the key/ display name. I put anyOf for the categories, does it do the same job? Is this how you will arrange items in the schema?
{
"$schema": "https://example.com/schema/dictionary",
"$id": "https://example.com/schemaoutput/dictionary",
"description": "A schema that validates the minimum requirements for validation output",
"type": "array",
"items": {
"additionalProperties": false,
"properties": {
"subcat1": {
"type": "string",
"title": "category1",
"tag": [
{
"display_labelA": [
"class_A"
],
"display_labelB": [
"class_B"
]
}
]
},
"subcat2": {
"type": "string",
"title": "category2",
"tag": [
{
"display_labelC": [
"class_C"
],
"display_labelD": [
"class_D"
]
}
]
}
},
"anyOf": [
{
"required": [
"subcat1",
"subcat2"
]
}
]
}
}
Edit:
As requested I updated the post with expected pass and fail scenarios. For example I want to create a json schema containing different categories of animals in the animal kingdom. Each key:value pair refer to the commonly known animal name and the corresponding scientific name. Only data entries of animals' commonly known names will be accepted.
Pass scenarios:
A data entry ‘human’ will be accepted, since it is one of the key:value pair (human: Homo sapiens) of category ‘primates’.
A data entry ‘chimpanzee’ will also be accepted. It is also one of the key:value pair (chimpanzee: pan troglodytes) of category ‘primates’.
A data entry ‘salmon’ will be accepted. Its key:value pair (Salmon: Salmo salar Linnaeus) is located in another category ‘fish’.
Fail scenarios:
Any data entry that are not listed in the animal kingdom dictionary will not be accepted e.g. Pear, Oranges, Table, Chairs…
Looking through 1 and other posts I think enum is what I need to map key:value pairs (i.e. biological name:commonly known name) under each category (primates or fish). I'm using anyOf at the end of the JSON schema to validate data entry that contain any values specified under any category.
{
"$schema": "https://example.com/schema/dictionary",
"$id": "https://example.com/schemaoutput/dictionary",
"description": "A schema that validates the minimum requirements for validation output",
"type": "array",
"items": {
"additionalProperties": false,
"properties": {
"subcat1": {
"type": "string",
"title": "category1",
"enum": [{
"display_labelA": "class_A",
"display_labelB": "class_B"
}]
},
"subcat2": {
"type": "string",
"title": "category2",
"enum": [{
"display_labelA": "class_A",
"display_labelB": "class_B"
}]
}
},
"anyOf": [{
"required": [
"subcat1",
"subcat2"
]
}]
}
}
Related
I have an array which includes objects which have different key values. I want to validate each object key. For example, age field can get only Equal and Not equal operator values. So "op" key is different for each key. For example name should be used with Contains operator.
[
{ age:21, op: "Equal" },
{ name:21, op: "Contains" },
{ date: 1564577662198, op: "Not equal" }
]
I have written a schema as,
{
"title": "ValidatorSchema",
"type": "array",
"items": {
"type": "object",
"properties": {
"age":{
"type": "number"
},
"operator" : {
"type" : "string",
"enum" : ["Equal" , "Not equal"]
},
"name":{
"type": "string"
},
"operator" : {
"type" : "string",
"enum" : ["Contains"]
}
}
}
}
But i couldn't relate each key with an operator. How can I do it?
Here's one way to express the requirements (as best I understand them) using the "JSON Extended Structural Schema" language, JESS:
[
["&",
{"comment": "https://stackoverflow.com/questions/57291339/validate-each-object-key-in-the-object-array-with-json-schema-in-ajv",
"::<=": {
"age": "number",
"operator": "string",
"name": "string",
"date": "number"
}
},
{ "comment": "age field can get only Equal and Not equal operator values",
"ifcond": { "has": "age"},
"then": ["&", {"forall": ".[operator]", "enumeration": ["Equal", "Not equal"]}]
},
{ "comment": "name should be used with Contains operator",
"ifcond": { "forall": ".[operator]", "equal": "Contains" },
"then": ["&", {"has": "name" } ]
}
]
]
Explanation
A JESS schema is a collection of JSON texts. Here, one JSON document suffices, as shown above.
The outer square brackets express the requirement that the target JSON entity must be a JSON array.
The "&" signifies that what follows is a conjunction of constraints. Here there are three top-level constraints, each with a "comment" field to indicate what's going on. In brief:
The first top-level constraint expresses the requirement that the components of the array must contain objects formed using any of the indicated keys with the type constraint shown.
The second top-level constraint expresses the condition that the "age field can get only Equal and Not equal operator values".
The third expresses the constraint that if the value of .operator is "Contains" in an object, then that object must have a "name" key (the type of which has already been specified in (1.)).
I have the following use-case I try to solve with JSON schemas.
I have a generic JSON data schema for, for example, a user. Here is an example of the user.schema.json file.
{
"type": "object",
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"email": {
"type": "string",
"minLength": 1
},
"locale": {
"type": "string",
"minLength": 1
},
"active": {
"type": "boolean",
"default": true
},
"password": {
"type": "string",
"minLength": 8
},
"roles": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
}
}
}
Now I have 2 different kinds of requests:
- POST: Add a user
- PATCH: Update user data.
In 1 case, I can send this data structure, with 3 required fields, while in case of a patch each field is optional.
So I get the post request file: post-user.schema.json:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "user.schema.json",
"required": [
"name",
"password",
"email"
]
}
And for my patch (path-user.schema.json:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "user.schema.json"
}
Now the issue that I am having is that my POST schema also marks a user like:
{
"name": "NoPassword",
"email": "nopassword#moba.nl",
"roles": []
}
Which is missing the required password field, as a valid JSON schema.
Apparently, this is not the way to assign required fields to a referenced data structure. I have tried to use google to see what I can find on the subject regarding this using searches like:
[ how to assign required field to referenced schema's ]
and I tried to obtain this info from the documentation.
I have no luck.
My questions now are:
A. Is it possible to assign required fields to a $referenced json schema data object.
B. If this is possible how to do it
C. If this is not possible, what would be a good way to approach this.
Any help is much appreciated.
Using $ref results in all other properties in the object being ignored, so you need to wrap your use of $ref.
Let's take a look at the spec:
An object schema with a "$ref" property MUST be interpreted as a
"$ref" reference. The value of the "$ref" property MUST be a URI
Reference. Resolved against the current URI base, it identifies the
URI of a schema to use. All other properties in a "$ref" object MUST
be ignored.
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-01#section-8.3
Then consider the schema you included in your question:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "user.schema.json",
"required": [
"name",
"password",
"email"
]
}
Reading the spec, you can see why required will be ignored.
Originally $ref was only designed to replace a WHOLE object, not ADD to the conditions for the object.
What you want is for multiple schemas to be applied to the instance. To do this, you use allOf.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"allOf": [
{
"$ref": "user.schema.json"
},
{
"required": [
"name",
"password",
"email"
]
}
]
}
I loaded this schema into a demo for you to test at https://jsonschema.dev - although it doesn't support references yet, so I transcluded the reference, but the validation will work the same.
From draft-8 onwards, $ref will behave as you expect, as it becomes an applicator keyword rather than a keyword with special behaviours, meaning other keywords in the same object will not need to be ignored.
I'm using the play-json-schema-validator and want to set up an integration test with scala in order to check an API's JSON response schema.
Certain fields of the response are nullable and I want to validate for that. So some field can be either a string or null yet it can never be a number.
Playing around on its playground I want to validate for an array of objects that each object's name property is either a string or null.
I came up with this schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product set",
"type": "array",
"items": {
"title": "Product",
"type": "object",
"properties": {
"name": {
"type": ["string", null]
}
}
}
}
Yet though it validates the string and null case, I now get a false positive for numbers. I was expecting an error for this json, yet it validates:
[
{
"name": "Red anger"
},
{
"name": null
},
{
"name": 13
}
]
How to declare a field of a type as nullable using schema validator?
Enquote the null in the schema:
"type": ["string", "null"]
You can read about that in the json schema validation documentation, i.e.:
6.1. Validation Keywords for Any Instance Type
6.1.1. type
The value of this keyword MUST be either a string or an array. If it is an array, elements of the array MUST be strings and
MUST be unique.
String values MUST be one of the six primitive types ("null",
"boolean", "object", "array", "number", or "string"), or "integer"
which matches any number with a zero fractional part.
An instance validates if and only if the instance is in any of the
sets listed for this keyword.
The type attribute of the schema does not accept arrays but only a single type at the time:
"string", "null"... and as you pointed out, the types should be strings so instead of null => "null"
If you want to check multiple types for a single field you need to use
anyOf, oneOf, allOf
Here is an example working with your input
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product set",
"type": "array",
"items": {
"title": "Product",
"type": "object",
"properties": {
"name": {
"anyOf": [
{"type":"string"},
{"type":"null"},
{"type":"number"}
]
}
}
}
}
Inside my root JSON object I have many JSON objects of two different types. I'm wondering if there is a way to write a JSON schema to validate these objects without getting specific, i.e. generic schema.
For example, imagine I have the following JSON:
"Profile":
{
"Name":
{
"Type": "String",
"Value": "Mike",
"Default": "Sarah",
"Description": "This is the name of my person."
}
"Age":
{
"Type": "Number",
"Value": 27,
"Default": 18,
"Description": "This is the age of my person."
}
}
This Profile JSON object represents a collection of various details about a person. Notice I have two different types of inner Objects, String Objects and Number Objects. Taking this into account, I would now like to create a JSON Schema to validate any of the inner objects without being specifc about which Objects they are, e.g. I don't care that we have "Name" or "Age", I care that we have proper String Objects and Number Objects.
Does JSON Schema give me the ability to do this? How do I write a generic JSON Schema based on the kinds of Objects I have and not specific object names?
Here is what I've got so far:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"StringObject": {
"type": "object",
"properties": {
"Type": {
"type": "string"
},
"Value": {
"type": "string"
},
"Default": {
"type": "string"
},
"Description": {
"type": "string"
}
},
"required": [
"Type",
"Value",
"Default",
"Description"
]
}
}
}
Inside my root JSON object I have many JSON objects of two different types. I'm wondering if there is a way to write a JSON schema to validate these objects without getting specific, i.e. generic schema.
Union types are defined to handle this:
A value of the "union" type is encoded as the value of any of the member types.
Union type definition - An array with two or more items which indicates a union of type definitions. Each item in the array may be a simple type definition or a schema.
{
"type":
["string","number"]
}
References
JSON Encoding of Data Modeled with YANG: 6.10. The "union" Type
A JSON Media Type for Describing the Structure and Meaning of JSON Documents: Union Types
I am designing the the json scheme. and I am facing some issues while designing the schema.
Here is the problem.
I have an array of group objects. and I want this array should contain unique group objects. I want to make them unique based on object id ( ex group.id)
The groups array is not unique if (groups[0].id == groups[1].id) , I want to make unique only based on group id, Below is my Json structure.
"groups": {
"type": "array",
"items": {"$ref": "#/group"},
"uniqueItems":true
},
"group": {
"type": "object",
"properties": {
"id": {"type": "integer"},
"type": {
"type": "string",
"enum": [
"a",
"b"
]
},
"command": {
"type": "string",
"enum": [
"add",
"modify"
]
}
}
},
Well, there is no magic bullet here. Remind Json-Schema is intended for defining structure of Json Data (not values).
One option would be not consider your groups node an "array" but instead an "object", and use additionalProperties to express that all additional properties should contain "type" and "command" properties.
Then you would use the name of each property in groups as id, so it would be unique.
The problem with this approach is that you do not restrict this id to be numeric (It might not be acceptable in your context). Even you could use patternProperties to match the "type,command" schema just to numeric "id's".