Reputation: 501
Here is my JSON Schema(hypothetical, as I cannot share my actual one) and the JSON. The if-then-else condition is like:
at a time only one (1) out of three (3) country can appear to define statistics.
Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"year",
"country",
"statistics"
],
"definitions": {
"statisticsUsa": {
"if": {
"properties": {
"type": {
"const": "statisticsUsa"
}
},
"required": [
"type"
]
},
"then": {
"properties": {
"type": {
"const": "statisticsUsa"
}
}
}
},
"statisticsFinland": {
"if": {
"properties": {
"type": {
"const": "statisticsFinland"
}
},
"required": [
"type"
]
},
"then": {
"properties": {
"type": {
"const": "statisticsFinland"
}
}
}
},
"statisticsGermany": {
"if": {
"properties": {
"type": {
"const": "statisticsGermany"
}
},
"required": [
"type", "literacy"
]
},
"then": {
"properties": {
"type": {
"const": "statisticsGermany"
},
"literacy": {
"type": "string"
}
}
}
}
},
"properties": {
"year": {
"type": "string"
},
"country": {
"type": "string",
"enum": [
"USA",
"FINLAND",
"GERMANY"
]
},
"statistics": {
"type": "array",
"allOf": [{
"if": {
"contains": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"statisticsUsa"
]
}
}
}
},
"then": {
"not": {
"contains": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"statisticsFinland",
"statisticsGermany"
]
}
}
}
}
},"errorMessage" :"Only USA applicable at a time for statistics"
},
{
"if": {
"contains": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"statisticsFinland"
]
}
}
}
},
"then": {
"not": {
"contains": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"statisticsUsa",
"statisticsGermany"
]
}
}
}
}
},"errorMessage" :"Only Finland applicable at a time for statistics"
},
{
"if": {
"contains": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"statisticsGermany"
]
}
}
}
},
"then": {
"not": {
"contains": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"statisticsUsa",
"statisticsFinland"
]
}
}
}
}
},"errorMessage" :"Only Germany applicable at a time for statistics"
}
],
"minItems": 1,
"items": {
"anyOf": [{
"$ref": "#/definitions/statisticsUsa"
},
{
"$ref": "#/definitions/statisticsFinland"
},
{
"$ref": "#/definitions/statisticsGermany"
}
]
}
}
}
}
Json 1
const Ajv = require('ajv');
const ajv = new Ajv({
allErrors: true,
jsonPointers: true
});
const schema1 = require("./sof.json");
require('ajv-errors')(ajv /*, {singleError: true} */);
const data = {
year: "2000",
country: "USA",
statistics: [
{"type":"statisticsUsa"},
{"type":"statisticsFinland"}
]
}
let valid = ajv.validate(schema1, data); //schema, data
if (!valid) {
console.log(`${JSON.stringify(ajv.errors,null,2)}`);
}
Here, I can see 2 errors as part of the array, when I have 2 countries. My question is, being 'finland' cannot have with 'USA', the error for "Only USA applicable at a time for statistics" is NOT acceptbale, as it satisfies the condition. But, The error for Findland is acceptable.
[
{
"keyword": "errorMessage",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/0/errorMessage",
"params": {
"errors": [
{
"keyword": "not",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/0/then/not",
"params": {},
"message": "should NOT be valid"
},
{
"keyword": "if",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/0/if",
"params": {
"failingKeyword": "then"
},
"message": "should match \"then\" schema"
}
]
},
"message": "Only USA applicable at a time for statistics"
},
{
"keyword": "errorMessage",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/1/errorMessage",
"params": {
"errors": [
{
"keyword": "not",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/1/then/not",
"params": {},
"message": "should NOT be valid"
},
{
"keyword": "if",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/1/if",
"params": {
"failingKeyword": "then"
},
"message": "should match \"then\" schema"
}
]
},
"message": "Only Finland applicable at a time for statistics"
}
]
Also, if I add 'Germany' in JSON as,
{
year: "2000",
country: "USA",
statistics: [
{"type":"statisticsUsa"},
{"type":"statisticsFinland"},
{"type":"statisticsGermany"}
]
}
it throws 3 errors as part of the array (See below). Why?
[
{
"keyword": "errorMessage",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/0/errorMessage",
"params": {
"errors": [
{
"keyword": "not",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/0/then/not",
"params": {},
"message": "should NOT be valid"
},
{
"keyword": "if",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/0/if",
"params": {
"failingKeyword": "then"
},
"message": "should match \"then\" schema"
}
]
},
"message": "Only USA applicable at a time for statistics"
},
{
"keyword": "errorMessage",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/1/errorMessage",
"params": {
"errors": [
{
"keyword": "not",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/1/then/not",
"params": {},
"message": "should NOT be valid"
},
{
"keyword": "if",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/1/if",
"params": {
"failingKeyword": "then"
},
"message": "should match \"then\" schema"
}
]
},
"message": "Only Finland applicable at a time for statistics"
},
{
"keyword": "errorMessage",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/2/errorMessage",
"params": {
"errors": [
{
"keyword": "not",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/2/then/not",
"params": {},
"message": "should NOT be valid"
},
{
"keyword": "if",
"dataPath": "/statistics",
"schemaPath": "#/properties/statistics/allOf/2/if",
"params": {
"failingKeyword": "then"
},
"message": "should match \"then\" schema"
}
]
},
"message": "Only Germany applicable at a time for statistics"
}
]
Upvotes: 1
Views: 1818
Reputation: 2147
You already deduced it yourself: the allOf
contains
applies all subschemas and checks against all array items.
If you want only one error message, then you should decide the priority of countries and only check in subsequent allOf
parts for the remaining countries and not all of them each time. E.g.
That way, you never get multiple of these errors at the same time.
Upvotes: 1