Json schema check all items enum are present in array of objects - json

I have json schema like this:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "array",
"items": {
"type": "object",
"properties": {
"country": {
"type": "string",
"maxLength": 2,
"enum": ["aa", "bb"]
}
},
"required": [
"country"
]
}
}
And json in this format:
[
{"country": "aa"},
]
I want schema to check whether the json file contains all countries listed in enum:
[
{"country": "aa"},
{"country": "bb"},
]
Is it possible?

You can do it with v5/6 contains keyword:
{
"allOf": [
{ "contains": { "properties": { "country": { "constant": "aa" } } } },
{ "contains": { "properties": { "country": { "constant": "bb" } } } }
]
}
"constant": "aa" is another v5/6 keyword, same as "enum": ["aa"].
At the moment Ajv supports these keyword (a bit of self promotion).

For those who can't use #esp handy syntax, here's an old style solution:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "array",
"items": {
"type": "object",
"properties": {
"country": {
"type": "string",
"maxLength": 2,
"enum": ["aa", "bb"]
}
},
"required": [
"country"
]
},
"allOf": [
{"not": {"items": {"not": {"properties": {"country": {"enum": ["aa"]}}}}}},
{"not": {"items": {"not": {"properties": {"country": {"enum": ["bb"]}}}}}}
]
}

Related

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 is not getting validated based on schema

I must be missing something here, but the below JSON is not getting validated against the schema.
For example, the required attribute from the Java/JavaScript object is never getting enforced as per the schema. (FYI- Every language object may have other attributes or nested object)
However, if I completely remove the definition and directly put under array items each separately, then it validates.
I want to use 'definitions' and gets validated.The reason I have to put all the object in definitions and later I may have to put different language object in oneOf/allOf for other certain validation check.
Online check:
Schema and JSON
JSON
{
"languages": [
{
"lang": "Java",
"trainer": "Peter"
},
{
"lang": "JavaScript",
"enrolled": "42",
"available": "5"
}
]
}
and the Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"languages"
],
"properties": {
"languages": {
"type": "array",
"minItems": 1,
"items": {
"type": "object"
},
"anyOf": [
{
"$ref": "#/definitions/Java"
},
{
"$ref": "#/definitions/JavaScript"
}
]
}
},
"definitions": {
"Java": {
"required": [
"trainer"
],
"properties": {
"lang": {
"enum": [
"Java"
]
},
"trainer": {
"type": "string"
}
}
},
"JavaScript": {
"required": [
"enrolled",
"available"
],
"properties": {
"lang": {
"enum": [
"JavaScript"
]
},
"enrolled": {
"type": "string"
},
"available": {
"type": "string"
}
}
}
}
}
The fixed schema and it works now
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"languages"
],
"properties": {
"languages": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"anyOf": [
{
"$ref": "#/definitions/Java"
},
{
"$ref": "#/definitions/JavaScript"
}
]
}
}
},
"definitions": {
"Java": {
"required": [
"trainer"
],
"properties": {
"lang": {
"enum": [
"Java"
]
},
"trainer": {
"type": "string"
}
}
},
"JavaScript": {
"required": [
"enrolled",
"available"
],
"properties": {
"lang": {
"enum": [
"JavaScript"
]
},
"enrolled": {
"type": "string"
},
"available": {
"type": "string"
}
}
}
}
}
I think that the "array" definition is not correct. The objects that can be added in the array must be refereed in the "items", after you define the type of the items. Something like this:
"languages": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"anyOf": [
{"$ref": "#/definitions/Java"},
{"$ref": "#/definitions/JavaScript"}
]
}
}
I have fixed myself
What I did: I have placed the json object blocks under items section of array.

JSON Schema oneOf for array options

I am trying to model the scenario where the JSON payload has a "steps" array and it's contents may be only one of predefined a set of options, for example:
{ "steps": ["s0"] }
or
{ "steps": ["s1"] }
or
{ "steps": ["s0", "s2"] }
How would I model this in a schema? The following:
{
"$id": "https://example.com/person.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Payload",
"type": "object",
"properties": {
"steps": {
"type": "array",
"oneOf": [
["s0"],
["s1"],
["s0", "s2"]
]
}
}
}
fails with "Unexpected token when reading schemas: StartArray. Path 'properties.steps.oneOf[0]'"
EDIT
Apologies for moving the goalposts, I simplified my problem to a point where the proposed solutions work for the simplified
version but not the original. The extra complication is that instead of string values I need to $ref objects sooo...
Sample inputs:
{ "steps": [{"name": "S0"}] }
or
{ "steps": [{"name": "S1"}] }
or
{ "steps": [{"name": "S1"}, {"name": "S2"}] }
A schema (following suggestion by #EylM) that doesn't match as expected
{
"$id": "https://example.com/person.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Request",
"type": "object",
"properties": {
"steps": {
"type": "array",
"oneOf": [
{
"const": [
{"$ref": "#/definitions/s0"}
]
},
{
"const": [
{"$ref": "#/definitions/s1"}
]
},
{
"const": [
{"$ref": "#/definitions/s1"},
{"$ref": "#/definitions/s2"}
]
}
]
}
},
"required": [
"steps"
],
"definitions": {
"s0": {
"type": "object",
"properties": {"name": { "const": "S0" }}
},
"s1": {
"type": "object",
"properties": {"name": {"const": "S1" }}
},
"s2": {
"type": "object",
"properties": {"name": { "const": "S2" }}
}
}
}
With this schema and input { "steps":[{"name": "s0"}] } I get
JSON is valid against no schemas from 'oneOf'
For whatever it's worth, I am using https://www.jsonschemavalidator.net/ for experimenting.
Updated my answer according to your edit. Following JSON schema validates all 3 conditions in the question and I assumed { "steps": [{"name": "S2"}, {"name": "S1"}] } is not valid. Correct me if I'm wrong.
{
"$id": "https://example.com/person.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Request",
"type": "object",
"properties": {
"steps": {
"type": "array",
"anyOf": [
{
"maxItems": 1,
"items": {
"oneOf": [
{
"$ref": "#/definitions/s0"
},
{
"$ref": "#/definitions/s1"
}
]
}
},
{
"minItems": 2,
"maxItems": 2,
"items": [
{
"$ref": "#/definitions/s1"
},
{
"$ref": "#/definitions/s2"
}
]
}
]
}
},
"required": [
"steps"
],
"definitions": {
"s0": {
"type": "object",
"properties": {
"name": {
"const": "S0"
}
}
},
"s1": {
"type": "object",
"properties": {
"name": {
"const": "S1"
}
}
},
"s2": {
"type": "object",
"properties": {
"name": {
"const": "S2"
}
}
}
}
}
In case you want to pass validation for { "steps": [{"name": "S2"}, {"name": "S1"}] } use another anyOf block as follows.
{
"minItems": 2,
"maxItems": 2,
"items": [
{
"$ref": "#/definitions/s2"
},
{
"$ref": "#/definitions/s1"
}
]
}
Try using enum keyword.
The enum keyword is used to restrict a value to a fixed set of values.
It must be an array with at least one element, where each element is
unique.
json-schema - More info.
In your case, JSON would look like:
{
"$id": "https://example.com/person.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Payload",
"type": "object",
"properties": {
"steps": {
"type": "array",
"oneOf": [
{"enum": ["s1"]},
{"enum": ["s0"]},
{"enum": ["s1, s2"]}
]
}
}
}

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

allow one of all based on the same base type

I have the following json schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "schema validating people and vehicles",
"definitions": {
"base": {
"properties": {
"age": {
"type": "integer"
}
},
"required": [
"age"
]
},
"person": {
"$ref": "#/definitions/base",
"additionalProperties": false,
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"sport": {
"type": "string"
}
},
"required": [
"firstName"
]
},
"vehicle": {
"$ref": "#/definitions/base",
"additionalProperties": false,
"properties": {
"vehicle": {
"type": "string"
},
"price": {
"type": "integer"
}
}
}
},
"type": "object",
"oneOf": [
{
"$ref": "#/definitions/person",
},
{
"$ref": "#/definitions/vehicle",
}
]
}
And i want it to validate against
{"firstName":"John", "lastName":"Doe", "sport": "football", "age": 15}
and the following
{"type": "car", "price": 100, "age": 3}
I get the following error JSON is valid against more than one schema from 'oneOf'. Valid schema indexes: 0, 1..
Why is it valid against more then one? (firstName is only defined in person and type is only defined in vehicle.)
JSON Schema doesn't support inheritance.
See:
https://github.com/json-schema-org/json-schema-spec/issues/348
https://spacetelescope.github.io/understanding-json-schema/reference/combining.html
JSon schema and Inheritance