I'm newbie about npm ajv
I have a question:
How many "switch" in a object json?
example:
var schema = {
"type": "object",
"switch": [
{
"if": {
"properties": {
"powerLevel": {"constant": false}
}
},
"then": {
"required": ["disbelief"]
}
},
{
"then": {
"required": ["confidence"]
}
}
],
"switch": [
{
"if": {
"properties": {
"power": {"constant": false}
}
},
"then": {
"required": ["disb"]
}
},
{
"then": {
"required": ["conf"]
}
}
]
};
I test with schema above in this link
it's just check end switch.
please help me! thanks!
You cannot have two keywords switch in the same object.
In this particular instance you can merge the "cases" in one switch:
{
"type": "object",
"switch": [
{
"if": { "properties": { "powerLevel": {"constant": false} } },
"then": { "required": ["disbelief"] }
},
{
"if": { "properties": { "power": {"constant": false} } },
"then": { "required": ["disb"] }
},
{
"then": {
"oneOf": [
{ "required": ["confidence"] },
{ "required": ["conf"] }
]
}
}
]
}
In general case you can use keywords allOf, anyOf, oneOf to merge two schemas containing duplicate keywords between them.
Related
I could not find any examples of this so I'm assuming it's not possible, but want to confirm.
I have a main schema that references other schemas:
https://www.jsonschemavalidator.net/s/4aLvXa4I
{
"$defs": {
"mainSchema": {
"$id": "https://example.com/person.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"type": "object",
"properties": {
"objectOne": {
"$ref": "#/$defs/objectOne"
},
"objectTwo": {
"$ref": "#/$defs/objectTwo"
}
}
},
"objectOne": {
"type": "object",
"properties": {
"checkThisValue": {
"type": "string",
"enum": [
"one",
"two",
"three"
]
}
}
},
"objectTwo": {
"type": "object",
"properties": {
"whenSettingThisValue": {
"type": "string",
"enum": [
"A",
"B",
"C"
]
}
}
}
},
"$ref": "#/$defs/mainSchema"
}
I want to define this rule:
IF objectOne.checkThisValue == one
THEN objectTwo.whenSettingThisValue MUST == A
Same for two=>B and three=>C
Is this possible somehow? How do I reference objectOne properties inside of objectTwo?
Edit
I tried to create an if rule for objectTwo that references objectOne here, but my syntax is wrong because it's not working. whenSettingThisValue is set to C and it's saying valid when it should be invalid: https://www.jsonschemavalidator.net/s/NNjEIhWW
"objectTwo": {
"type": "object",
"properties": {
"whenSettingThisValue": {
"type": "string",
"enum": [
"A",
"B",
"C"
]
}
},
"if": {
"properties": {
"objectOne": {
"checkThisValue": {
"const": "one"
}
}
}
},
"then": {
"properties": {
"objectTwo": {
"whenSettingThisValue": {
"const": "A"
}
}
}
}
}
},
I also tried using a oneOf rule in mainSchema where both the subschemas are used, but it is not working either (this example should be invalid): https://www.jsonschemavalidator.net/s/WkmMasDC
"mainSchema": {
"$id": "https://example.com/person.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"additionalProperties": false,
"type": "object",
"properties": {
"objectOne": {
"$ref": "#/$defs/objectOne"
},
"objectTwo": {
"$ref": "#/$defs/objectTwo"
}
},
"oneOf": [
{
"type": "object",
"properties": {
"objectOne": {
"checkThisValue": {
"const": "one"
}
},
"objectTwo": {
"whenSettingThisValue": {
"const": "A"
}
}
}
}
]
},
Solution
Per answer my OneOf rule was malformed. This correctly checks a value in one object is set in response to another. I thought because I was referencing them in another schema with $ref I would have to do something special, but I don't.
https://www.jsonschemavalidator.net/s/HcVhrShk
"oneOf": [
{
"type": "object",
"properties": {
"objectOne": {
"properties": {
"checkThisValue": {
"const": "one"
}
}
},
"objectTwo": {
"properties": {
"whenSettingThisValue": {
"const": "A"
}
}
}
}
},
{
"type": "object",
"properties": {
"objectOne": {
"properties": {
"checkThisValue": {
"const": "two"
}
}
},
"objectTwo": {
"properties": {
"whenSettingThisValue": {
"const": "B"
}
}
}
}
}
]
},
Yes you can. There is an if/then/else construct which takes schemas as its arguments, so you can define a rule "if property A exists with value X, then property B must exist with value Y" etc.
There are some examples here:
https://json-schema.org/understanding-json-schema/reference/conditionals.html#if-then-else
edit:
in your re-edit, change the oneOf clause to this:
"oneOf": [
{
"type": "object",
"properties": {
"objectOne": {
"properties": {
"checkThisValue": {
"const": "one"
}
}
}
}
},
{
"type": "object",
"properties": {
"objectTwo": {
"properties": {
"whenSettingThisValue": {
"const": "A"
}
}
}
}
}
]
I have three fields, foo, bar, baz. bar depends on foo, baz depends on bar:
foo is bool
if foo is not provided bar & baz are forbidden
foo = true: bar is required enum with values bar1 & bar2
foo = false: bar & baz are forbidden
foo = true & bar = bar1: baz is a required object with required field baz1 and non-required field baz2 both string
foo = true & bar = bar2: baz is a required object with required field baz3 string
So I started building this iteratively. So far, I've got
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"foo": {
"type": "boolean"
}
},
"allOf": [
{
"if": {
"not": {
"required": ["foo"]
}
},
"then": {
"not": {
"required": ["bar", "baz"]
}
}
},
{
"if": {
"properties": {
"foo": {
"const": true
}
},
"required": ["foo"]
},
"then": {
"properties": {
"bar": {
"enum": ["bar1", "bar2"]
}
},
"required": ["bar"]
}
},
{
"if": {
"properties": {
"foo": {
"const": false
}
},
"required": ["foo"]
},
"then": {
"not": {
"required": ["bar", "baz"]
}
}
},
{
"if": {
"properties": {
"bar": {
"const": "bar1"
}
},
"required": ["bar"]
},
"then": {
"properties": {
"baz": {
"type": "object",
"properties": {
"baz1": { "type": "number" },
"baz2": { "type": "string" }
},
"required": ["baz1", "baz2"],
"additionalProperties": false
}
},
"required": ["baz"]
}
},
{
"if": {
"properties": {
"bar": {
"const": "bar2"
}
},
"required": ["bar"]
},
"then": {
"properties": {
"baz": {
"type": "object",
"properties": {
"baz3": { "type": "number" },
"baz4": { "type": "string" }
},
"required": ["baz3", "baz4"],
"additionalProperties": false
}
},
"required": ["baz"]
}
}
]
}
It correctly validates all combinations I've tried so far except when baz is present without foo & bar or with foo = false & no bar, which both validate to true even though I'd expect it to be false as both bar & baz are set as not require if foo is not required & if foo is false. What am I missing?
You should split up the required clauses so they check one keyword at a time.
"required": ["bar", "baz"] will be false if neither 'bar' nor 'baz' are present, which is what you want, but it will also be false if one property is present and the other is not, which is not (because you then wrap that check with a "not", making the "if" condition true).
Therefore, change that check to:
"allOf": [
{ "required": ["bar"] },
{ "required": ["baz"] }
]
Based on Ether's answer I've got this, it appears to be working as intended, so I'm providing it for ease of references for anybody who might need it in future:
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"foo": {
"type": "boolean"
}
},
"allOf": [
{
"if": {
"not": {
"required": ["foo"]
}
},
"then": {
"allOf": [
{
"not": {
"required": ["bar"]
}
},
{
"not": {
"required": ["baz"]
}
}
]
}
},
{
"if": {
"properties": {
"foo": {
"const": true
}
},
"required": ["foo"]
},
"then": {
"properties": {
"bar": {
"enum": ["bar1", "bar2"]
}
},
"required": ["bar"]
}
},
{
"if": {
"properties": {
"foo": {
"const": false
}
},
"required": ["foo"]
},
"then": {
"allOf": [
{
"not": {
"required": ["bar"]
}
},
{
"not": {
"required": ["baz"]
}
}
]
}
},
{
"if": {
"properties": {
"bar": {
"const": "bar1"
}
},
"required": ["bar"]
},
"then": {
"properties": {
"baz": {
"type": "object",
"properties": {
"baz1": { "type": "number" },
"baz2": { "type": "string" }
},
"required": ["baz1", "baz2"],
"additionalProperties": false
}
},
"required": ["baz"]
}
},
{
"if": {
"properties": {
"bar": {
"const": "bar2"
}
},
"required": ["bar"]
},
"then": {
"properties": {
"baz": {
"type": "object",
"properties": {
"baz3": { "type": "number" },
"baz4": { "type": "string" }
},
"required": ["baz3", "baz4"],
"additionalProperties": false
}
},
"required": ["baz"]
}
}
]
}
This question already has an answer here:
Is there support in JSON Schema for deep object validation?
(1 answer)
Closed 1 year ago.
I have base json schema base.schema.json
{
"$id": "base.schema.json",
"type": "object",
"properties": {
"remote_os": {
"default": "Windows",
"enum": [
"Linux",
"Windows" ]
}
},
"required": ["remote_os"]
}
Now referenced the schema definition in another json
{
"$id": "update.schema.json",
"properties": {
"common_data": {
"$ref": "base.schema.json"
}
},
"allOf": [
{
"if": {
"properties": {
"common_data": {
"remote_os": {
"const": "Windows"
}
}
}
},
"then": {
"properties": {
"file": {
"pattern": "^(.*.)(exe)$"
}
}
}
},
{
"if": {
"properties": {
"common_data": {
"remote_os": {
"const": "Linux",
"required": [
"remote_os"
]
}
}
}
},
"then": {
"properties": {
"file": {
"pattern": "^(.*.)(bin)$"
}
}
}
}
]
}
Basically adding the if-else logic to make sure for remote_os=Linux file should ended up with .bin and remote_os=Windows file should ended up with .exe
Now I am trying to validate against below data
{
"common_data": {
"remote_os": "Linux"
},
"file": "abc.bin"
}
[<ValidationError: "'abc.bin' does not match '^(.*.)(exe)$'">]. Not sure what's wrong here
I think you are over complicating it - surly just if/then/else?
{
"if": {
"properties": { "common_data": "properties": { "remote_os": { "const": "Windows" } } }
},
"then": {
"properties": { "file": { "pattern": "^(.*.)(exe)$" } }
},
"else": {
"properties": { "file": { "pattern": "^(.*.)(bin)$" } }
}
}
I have following JSON schema
{
"type": "object",
"additionalProperties": true,
"if":
{
"properties":
{
"battery":
{
"type": "object",
"additionalProperties": false,
"minLength":1,
"properties":
{
"cell_composition":
{
"type": "object",
"additionalProperties": false,
"properties":
{
"value":
{
"enum": ["lithium", "lithium_cobalt"]
}
}
}
}
}
}
} ,
"then":
{
"required": ["number_of_lithium_ion_cells"]
}
}
Below is the JSON data
{
"battery123":
{
"cell_composition":
{
"value": "lithium_polymer"
}
}
}
I got below error
Message:
Required properties are missing from object:
number_of_lithium_ion_cells. Schema path:
#/then/required
Actually when "battery" attribute exist then it works fine.
when "battery" attribute does not exist it should give above mentioned error.
How can I add above condition then it will works on both above mentioned cases.
I have checked your both schemas with JavaScript (see snipet below) and the result is: your both schemas are absolutelly OK. You have to find your mistake not in JSON schemas.
var jObj1 =
{
"type": "object",
"additionalProperties": true,
"if":
{
"properties":
{
"battery":
{
"type": "object",
"additionalProperties": false,
"minLength":1,
"properties":
{
"cell_composition":
{
"type": "object",
"additionalProperties": false,
"properties":
{
"value":
{
"enum": ["lithium", "lithium_cobalt"]
}
}
}
}
}
}
} ,
"then":
{
"required": ["number_of_lithium_ion_cells"]
}
}
var test1 = JSON.parse(JSON.stringify(jObj1));
console.log(test1);
var jObj2 =
{
"battery123":
{
"cell_composition":
{
"value": "lithium_polymer"
}
}
}
var test2 = JSON.parse(JSON.stringify(jObj2));
console.log(test2);
I'm just reading through the more advanced validators in the Schema definition of the Swagger specification:
{
"Schema":{
"type":"object",
"properties":{
"title":{
"type":"string"
},
"multipleOf":{
"type":"number",
"minimum":0,
"exclusiveMinimum":true
},
"maximum":{
"type":"number"
},
"exclusiveMaximum":{
"type":"boolean",
"default":false
},
"minimum":{
"type":"number"
},
"exclusiveMinimum":{
"type":"boolean",
"default":false
},
"maxLength":{
"type":"integer",
"minimum":0
},
"minLength":{
"type":"integer",
"minimum":0,
"default":0
},
"pattern":{
"type":"string",
"format":"regex"
},
"maxItems":{
"type":"integer",
"minimum":0
},
"minItems":{
"type":"integer",
"minimum":0,
"default":0
},
"uniqueItems":{
"type":"boolean",
"default":false
},
"maxProperties":{
"type":"integer",
"minimum":0
},
"minProperties":{
"type":"integer",
"minimum":0,
"default":0
},
"required":{
"type":"array",
"items":{
"type":"string"
},
"minItems":1,
"uniqueItems":true
},
"enum":{
"type":"array",
"items":{
},
"minItems":1,
"uniqueItems":true
},
"type":{
"type":"string",
"enum":[
"array",
"boolean",
"integer",
"number",
"object",
"string"
]
},
"not":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
},
"allOf":{
"type":"array",
"items":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
}
},
"oneOf":{
"type":"array",
"items":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
}
},
"anyOf":{
"type":"array",
"items":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
}
},
"items":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
},
"properties":{
"type":"object",
"additionalProperties":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
}
]
}
},
"additionalProperties":{
"oneOf":[
{
"$ref":"#/definitions/Schema"
},
{
"$ref":"#/definitions/Reference"
},
{
"type":"boolean"
}
],
"default":true
},
"description":{
"type":"string"
},
"format":{
"type":"string"
},
"default":{
},
"nullable":{
"type":"boolean",
"default":false
},
"discriminator":{
"$ref":"#/definitions/Discriminator"
},
"readOnly":{
"type":"boolean",
"default":false
},
"writeOnly":{
"type":"boolean",
"default":false
},
"example":{
},
"externalDocs":{
"$ref":"#/definitions/ExternalDocumentation"
},
"deprecated":{
"type":"boolean",
"default":false
},
"xml":{
"$ref":"#/definitions/XML"
}
},
"patternProperties":{
"^x-":{
}
},
"additionalProperties":false
}
}
The thing that I am thinking about is combinations of the anyOf, allOf, oneOf and not keywords. I have two questions.
The first question is: "can they be used in conjunction"? Like so:
{
"allOf" : [
{
"minItems" : 0
},
{
"maxItems" : 10
}
],
"anyOf" : [
{
"type" : "array",
"items" : {
"type" : "string"
}
},
{
"type" : "array",
"items" : {
"type" : "integer"
}
}
]
}
This example is, of course, needlessly complicated. But is it valid? Or can you only use one modifier but not the others?
The second question is, can anybody point me to a real-world example where one of these operators have been used in conjunction?
The thing that I am thinking about is combinations of the anyOf, allOf, oneOf and not keywords. I have two questions.
The first question is: "can they be used in conjunction"?
Yes, allOf, anyOf, oneOf and not can be used in conjunction. OpenAPI Specification follows the rules of JSON Schema here, and in JSON Schema adjacent keywords work as branches of an implicit allOf (source). So your example is equivalent to:
{
"allOf": [
{
"allOf": [
{
"minItems": 0
},
{
"maxItems": 10
}
]
},
{
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "array",
"items": {
"type": "integer"
}
}
]
}
]
}
That said, this example is too complex and can be simplified into:
{
"minItems": 0,
"maxItems": 10,
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
}
}