Referring child nodes in allOf if then condition in parent node - json

{
"$schema":"https://json-schema.org/draft/2019-09/schema",
"$id":"PersonalDetails.json",
"type":"object",
"properties":{
"Header":{
"type":"object",
"properties":{
"HeaderName":{
"type":"string"
},
"HeaderValue":{
"type":"string"
}
}
},
"Details":{
"type":"array",
"items":{
"type":"object",
"properties":{
"FName":{
"type":"string"
},
"LName":{
"type":"string"
},
"Address":{
"type":"object",
"properties":{
"FlatNo":{
"type":"string"
},
"Sector":{
"type":"string"
},
"LandMarks":{
"type":"object",
"properties":{
"LandMark1":{
"type":"string"
},
"LandMark2":{
"type":"string"
}
}
}
},
"required":[
"Sector"
]
}
}
}
}
}
}
{
"Header":{
"HeaderName":"DummyName",
"HeaderValue":"DummyName"
},
"Details":[
{
"FName":"Chicago",
"LName":"Laos",
"Address":{
"FlatNo":"Excalibur",
"Sector":"07",
"LandMarks":{
"LandMark1":"USA",
"LandMark2":"UK"
}
}
}
]
}
So the requirement is to insert IF then conditions in Json Schema with following conditions
if LandMark1 = USA and FlatNo = Excalibur
then Sector is required
I am not able to figure out where exactly should i place this condition and its syntax
i tried using $ref in if then conditions in allOf in Details as its parent for both Address and LandMarks
but even that didn't work as it was not able to figure out reference
Any help is highly apprecitiable

You'll need to use the if/then keywords to describe this. The hard part is the if schema.
You need to define an if schema that will validate to true when given an instance where your conditions are met. It can help to develop this schema separately and then add it to your full schema.
{
"type": "object",
"properties": {
"FlatNo": { "const": "Excalibur" },
"LandMarks": {
"type": "object",
"properties": {
"LandMark1": { "const": "USA" }
},
"required": ["LandMark1"]
}
},
"required": ["LandMarks", "FlatNo"]
}
The following instance would pass validation against that schema. It would fail if FlatNo != Excalibur or LandMark1 != USA.
{
"FlatNo":"Excalibur",
"Sector":"07",
"LandMarks":{
"LandMark1":"USA",
"LandMark2":"UK"
}
}
Now it should be trivial to apply if/then to your address schema.
"if": { ... schema from above ... },
"then": { "required": ["Sector"] }

Related

Validating flattened json keys and schemas

Im trying to find a way to validate flattened json-keys. For example, lets say I have a schema defined as below:
{
"$schema":"http://json-schema.org/draft-04/schema#",
"title":"Employee",
"type":"object",
"additional_properties":false,
"properties":{
"emp_category":{
"type":"string",
"oneOf":[
{
"enum":[
"INDIVIDUAL_CONTRIBUTOR",
"MANAGER"
]
}
]
},
"id":{ "type":"string" },
"emp_meta":{
"oneOf":[
{ "$ref":"#/definitions/IndividualContributor" },
{ "$ref":"#/definitions/Manager" }
]
}
},
"required":[
"emp_category",
"id"
],
"definitions":{
"IndividualContributor":{
"title":"IndividualContributor",
"type":"object",
"properties":{
"name":{ "type":"string" },
"id":{ "type":"string" },
"department":{ "type":"string" },
"managed_by":{ "type":"string" }
},
"required":[
"id",
"department",
"managed_by"
]
},
"Manager":{
"title":"Manager",
"type":"object",
"properties":{
"name":{ "type":"string" },
"id":{ "type":"string" },
"department":{ "type":"string" },
"managed_by":{ "type":"string" },
"manages":{
"type":"array",
"items":{ "type":"string" }
}
},
"required":[
"id",
"department",
"managed_by"
]
}
}
}
Now, we want to expose some upstream REST API to be able to query over objects pertaining to above schemas, lets say we have a REST payload as below:
{
"empoloyee":{
"AND":[
{ "emp_category":"MANAGER" },
{ "emp_meta.department":"R&D" },
{ "emp_meta.manages":"John*" }
]
}
}
So, I am wondering if theres a generalized way to validate flattened json keys that are part of the query payload. I've tried to parse (dfs) the query payload by leaf and convert it into a dict object and validate against the schema. But required fields are making this quite challenging. So, wondering if theres a way to go about it. I'm open to considering a different design as well, especially as keys and objects can become deeply nested.

Json schema validating wrong instance as true

I have the following schema and I'm having a hard time trying to understand why it is not working.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://yourdomain.com/schemas/myschema.json",
"title": "Product",
"description": "A product in the catalog",
"type": "object",
"properties": {
"transitions" : {
"description": "defines the transitions to another state",
"type": "object",
"patternProperties": {
"^[0-9]+$": {
"description": "defines a transition for an specific node",
"type":"object",
"properties": {
"next": {
"description": "id of the next transition",
"oneOf": [
{
"type":"string"
},
{
"type": "object",
"patternProperties": {
"^[\\<\\>\\=\\!\\=\\>\\<]\\_[0-9]+$" : {
"type":"string"
}
}
},
{
"type": "object",
"patternProperties": {
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
]
},
"action": {
"description": "id of the transitions action",
"type":"string"
}
}
}
},
"additionalProperties": false
}
},
"required": ["transitions"]
}
For example, as you can see in the schema, this particular json instance should comply with one of next property definitions
"transitions": {
"1": {
"action": "1_input",
"next": {
"test de una novedad": "2"
}
}
}
}
schema for property
{
"type": "object",
"patternProperties": {
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
But I got these error messages in an online validator https://www.jsonschemavalidator.net/,
Message:
JSON is valid against more than one schema from 'oneOf'. Valid schema indexes: 1, 2.
Schema path:
http://yourdomain.com/schemas/myschema.json#/properties/transitions/patternProperties/^[0-9]+$/properties/next/oneOf
Message:
Invalid type. Expected String but got Object.
Schema path:
http://yourdomain.com/schemas/myschema.json#/properties/transitions/patternProperties/^[0-9]+$/properties/next/oneOf/0/type
I don't see how it can be a match with two of the definitions.
Has anyone had a similar situation?
Thanks in advance
Your problem is with the definition of the oneOf
"oneOf": [
{
"type":"string"
},
{
"type": "object",
"patternProperties": {
"^[\\<\\>\\=\\!\\=\\>\\<]\\_[0-9]+$" : {
"type":"string"
}
}
},
{
"type": "object",
"patternProperties": {
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
]
For "test de una novedad": "2" both second and third element are objects with no property restriction, so it matches both.
To fix this you could try merging both if you don't mind possibly having an object validated with both properties:
"oneOf": [
{
"type":"string"
},
{
"type": "object",
"patternProperties": {
"^[\\<\\>\\=\\!\\=\\>\\<]\\_[0-9]+$" : {
"type":"string"
},
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
]
Or you could add additionalProperties: false in one or both.
"oneOf": [
{
"type":"string"
},
{
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^[\\<\\>\\=\\!\\=\\>\\<]\\_[0-9]+$" : {
"type":"string"
}
}
},
{
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
]

Json generic object type

I'd like to define an object something like this, to map to something like a java Map (but not exactly, since this needs to interface with typescript as well). Ultimately, what I'm trying to figure out is how to declare the <T> type of something (say Dict<MyObj>) in another object (if this is even possible):
(this is obviously not a valid json schema)
{
"type": "object",
"javaType": "some.package.base.DictKeyValuePair",
"properties": {
"key": { "type": "string" },
"value": { "type": "<T>" }
}
}
which would be referenced in other json schemas something like this:
{
"type": "object",
"javaType": "some.package.base.Dict",
"properties": {
"key": { "type": "string" },
"value": { "type": "<T>" },
"keValuePairs": {
"type": "array",
"items": {
"$ref": "DictKeyValuePair.json",
"genericType": "<T>"
}
}
}
}
finally being used in an object similar to this:
{
"type": "object",
"javaType": "some.package.SomeObject",
"properties": {
"someDict": {
"$ref": "Dict.json",
"genericType": "SomeObjectOrSimpleType"
}
}
}
So... is this possible in a json schema?
It is possible to do something like that using json-schema but you need to define the schemas, take a look to this samples:
http://json-schema.org/learn/examples/address.schema.json
{
"$id":"https://example.com/address.schema.json",
"$schema":"http://json-schema.org/draft-07/schema#",
"description":"An address similar to http://microformats.org/wiki/h-card",
"type":"object",
"properties":{
"post-office-box":{
"type":"string"
},
"extended-address":{
"type":"string"
},
"street-address":{
"type":"string"
},
"locality":{
"type":"string"
},
"region":{
"type":"string"
},
"postal-code":{
"type":"string"
},
"country-name":{
"type":"string"
}
},
"required":[
"locality",
"region",
"country-name"
],
"dependencies":{
"post-office-box":[
"street-address"
],
"extended-address":[
"street-address"
]
}
}

json schema to validate array of objects with anyOf and oneOf requirements

I am trying to define a json schema to limit the properties of objects conatined in an array.
What I have so far is:
{
"title":"myCollection",
"properties":{
"things":{
"type":"array",
"items":[{
"title":"thingObj",
"type":"object",
"properties":{
"name":{
"type":"string"
},
"code":{
"type":"string"
},
"type":{
"type":"string",
"enum":["dog","cat"]
},
"rate":{
"type":"number"
},
"value":{
"type":"number"
}
},
"anyOf":[{
"properties":{
"name":{
"type":"string"
}
},"required":["name"]
},{
"properties":{
"code":{
"type":"string"
}
},"required":["code"]
},{
"properties":{
"type":{
"type":"string",
"enum":["new","existing"]
}
},"required":["type"]
}],
"oneOf":[{
"properties":{
"rate":{
"type":"number"
}
},
"required":["rate"]
},{
"properties":{
"value":{
"type":"number"
}
},
"required":["value"]
}],
"additionalProperties":false
}]
}
}
}
Now given the following jsonobj:
{
"things": [
{
"name": "tabby",
"code": "meeow",
"type": "cat",
"value": 20
},
{
"name": "k9",
"code": "woofer",
"type": "dog",
"rate": 15
}
]
}
This json schema validator delivers a valid response but this validation only seems to apply to the first element in the array. If you remove all the fields included in the anyOf clause or the oneOf clause on the first element then validation fails. The same on the second array element does not raise the desired failure. How can I ensure the validation is run against each array member?
This is because you have (accidentally) used "tuple typing". This is enabled when the value of "items" is an array, and it matches schemas to specific positions in the array.
If you change "items" (in your schema) to be simply a schema (not an array of schemas), then it will validate all items the same way.
Kudos to #cloudfeet 's answer, I was struggling with this issue until I saw his answer.
To be more clear, the [] around items should be removed.
{
"title":"myCollection",
"properties":{
"things":{
"type":"array",
"items":**[**{
"title":"thingObj",
"type":"object",
.
.
.
"required":["value"]
}**]**,
"additionalProperties":false
}]
}
}
}

JSON Schema away to specify an "any"-type schema with certain required fields

Let's say I have the following JSON Schema
{
"name":"Product",
"type":"object",
"properties":{
"id":{
"type":"number",
"required":true
},
"name":{
"description":"Name of the product",
"required":true
},
"price":{
"required":true,
"type": "number",
"minimum":0,
"required":true
},
"tags":{
"type":"array",
"items":{
"type":"any"
}
}
}
}
But, instead of tags being an array, I'd like it to be part of the root schema. So you could specify any property, but I give special attention to "id", "name" and "price"
Which of the following would be the correct way of doing it, and which ones are completely wrong?
{
"name":"Product",
"type":"object",
"properties":{
"id":{
"type":"number",
"required":true
},
"name":{
"description":"Name of the product",
"required":true
},
"price":{
"required":true,
"type": "number",
"minimum":0,
"required":true
}
},
"additionalProperties": {
"type":"any"
}
}
{
"name":"Product",
"type":"object",
"properties":{
"id":{
"type":"number",
"required":true
},
"name":{
"description":"Name of the product",
"required":true
},
"price":{
"required":true,
"type": "number",
"minimum":0,
"required":true
}
},
"extends": {
"type":"any"
}
}
{
"name":"Product",
"type":["object","any"],
"properties":{
"id":{
"type":"number",
"required":true
},
"name":{
"description":"Name of the product",
"required":true
},
"price":{
"required":true,
"type": "number",
"minimum":0,
"required":true
}
}
}
I can come up with a few more (such as inverting roles of "any" and "object"), but they are all derivative of these three examples.
[disclaimer: author of the next JSON Schema validation spec here]
OK, it is unclear what you ask, see below, but one of your examples clearly does not do what you want, this is the one where you write:
{ "type": [ "object", "any" ] }
This is equivalent to an empty schema, and as such validates each and every instance.
One way I read your question is that you want your JSON data to be either a tag array or an object with at least members named id, name and price. Since you seem to be using draft v3, you only have one solution:
{
"type": [
{
"description": "schema for tags array here",
},
{
"description": "schema for the base object here"
}
]
}
This construct means that the instance must obey at least one schema inside type (and you can mix it with primitive types as well).
However: the current draft now being v4, you should now write:
{
"anyOf": [
{
"description": "schema for tags array here",
},
{
"description": "schema for the base object here"
}
]
}
Note that not all implementations support draft v4, or the construct for type above. In fact, very few do. See below for a link to an online schema validator which supports both.
Another way that I read your question is that you want to allow properties other than id, name and price to be whatever they like. This is then quite simple. Just don't define a schema for tags in properties:
{
"type": "object",
"required": [ "id", "name", "price" ]
"properties": {
"id": {
"type": "number"
},
"name": {
"description": "Name of the product"
},
"price": {
"type": "number",
"minimum": 0
}
}
}
Since you don't specify additionalProperties as being false, the object instance can have any number of additional members, and these members can be anything.
Link to an online validator which can test your schemas: here