JSONSchema how to define a schema for a dynamic object - json

I have a JSON response that I am trying to create a JSONSchema for
{
"gauges": {
"foo": {
"value": 1234
},
"bar": {
"value": 12.44
}
}
}
It is important to know that the objects in the associative array gauges are dynamically generated so there can be zero to many. Each object in gauges will always have a value property and it will always be a number.
So each these are valid
Example 1
{
"gauges": {
"foo": {
"value": 1234
}
}
}
Example 2
{
"gauges": {
"dave": {
"value": 0.44
},
"tommy": {
"value": 12
},
"steve": {
"value": 99999
}
}
}
Example 3
{
"gauges": {}
}
I have looked though the specification and if this was an array I know I could use anyOf but I am unsure how to do this or if it is even possible.
NB I cannot change the format of the JSON

Conceptually what you want is an object representing a Typed Map.
The difficulty is that you have no named property to put your specification in the schema, but in that case You can use "additionalProperties"
{
"type": "object",
"properties": {
"gauges": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"value": {"type": "number"}
}
}
}
}
}
"gauges" property is defined as an object in which every "additionalProperties" will have a type containing a value of type number.
Note: In java you would serialize it to a Map<String,Value> with Value the classe containing a value. (don't know for other typed language, but I am open to suggestions)
This answer point to an analog solution
How to define JSON Schema for Map<String, Integer>?

Related

How to sort a JSON object with sub-objects based on an attribute of its sub-objects?

I have a list of objects that I need to index into by one of its attributes, the name in the below example. So I'm storing the list as an object instead of an array:
{
"Foo": {
"name": "Foo",
"date": "2022-08-21"
},
"Bar": {
"name": "Bar",
"date": "2022-08-20"
}
}
How can I sort the sub-objects by a different property of theirs (i.e. date in the above example), when serializing this JSON?
By definition, the keys within a JSON object are semantically unordered, so implementations are not required to support explicit sorting of such keys in any way.
However, as of version 1.4, jq does preserve the order of keys within objects, and also respects the order in which they are added. So, for the problem at hand, it becomes a matter of converting the above representation into an array, sorting it, and converting it back to a JSON object:
jq 'to_entries | sort_by(.value.date) | from_entries'
Explanation
First, convert the object with sub-objects into an array of key/value pairs with to_entries. The input becomes:
[
{
"key": "Foo",
"value": {
"obj1.name": "Foo",
"obj1.date": "2022-08-21"
}
},
{
"key": "Bar",
"value": {
"obj2.name": "Bar",
"obj2.date": "2022-08-20"
}
}
]
Since we now have an array, we can sort it with an arbitrary sub-object selector in sort_by, in my example, by .value.date, the output becomes:
[
{
"key": "Bar",
"value": {
"obj2.name": "Bar",
"obj2.date": "2022-08-20"
}
},
{
"key": "Foo",
"value": {
"obj1.name": "Foo",
"obj1.date": "2022-08-21"
}
}
]
Now it's a matter of converting the key/value form back to the object form with from_entries. The output becomes:
{
"Bar": {
"name": "Bar",
"date": "2022-08-20"
},
"Foo": {
"name": "Foo",
"date": "2022-08-21"
}
}

Is there support in JSON Schema for deep object validation?

I was looking around the docs and couldn't find any direct or indirect solution.
Is there any way to get validation on JSON objects without knowing exactly where the specific object is located?
For example, I want to validate the following sub-object:
{
"grandParent": {
"parent": {
"child": {
"name": "John"
}
}
}
}
The object can be part of a larger JSON file the can be structured as follows:
{
"root": {
"someKey": {
"grandParent": ...
},
"grandParent": ...,
...<go in even deeper>: {
"grandParent": ...
}
}
}
Can I create a json schema that validates the object no matter where it is?
Similar example in glob would be: root.**.grandParent.parent.child
You'll need to use a combination of additionalProperties, items, and recursive references.
First, we define the structure you want to validate. You have to define properties for each layer of the object.
Next, you want your root level to reference that definition. Because you're using pre draft 2019-09, you'll need to wrap that reference in an allOf.
Then you want to make sure that for objects, the values have the root schema applied, and for arrays, each item has the root schema applied.
The use of "$ref": "#" resolves to the root of the schema, which creates the cyclical reference.
Some implementations may not like this, but most should be able to handle it.
Here's a live demo of the below schema: https://jsonschema.dev/s/lBrZk
{
"$schema": "http://json-schema.org/draft-07/schema",
"definitions": {
"grandParentToChild": {
"properties": {
"grandParent": {
"properties": {
"parent": {
"properties": {
"child": {
"properties": {
"name": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"allOf": [
{
"$ref": "#/definitions/grandParentToChild"
}
],
"additionalProperties": {
"$ref": "#"
},
"items": {
"$ref": "#"
}
}

jsonSchema validating numerical keys by pattern

Could you help me, how I can validate "keys"(ex. "1","2","3") of list items in following json:
{
"list" : {
"1" : {
"element1" : "1",
"element2" : "2"
},
"2" : {
"element1" : "1",
"element2" : "2"
},
....
"512" : {
"element1" : "1",
"element2" : "2"
}
}
}
Please give me common examples to validate keys in json, too.
JSON Schema has three ways to constraint the property names of an object.
properties
The properties keyword allows you to set an exact match for property names.
{
"type": "object",
"properties": {
"1": { ... },
"2": { ... },
...
}
}
patternProperties
The patternProperties keyword constrains any property name that matches a regular expression to validate against a given schema.
{
"type": "object",
"patternProperties": {
"[1-9][0-9]*": { ... }
}
}
propertyNames
The propertyNames keyword constraints property names to match the given schema.
{
"type": "object",
"propertyNames": {
"pattern": "[1-9][0-9]*"
}
}
Edit 12-19-2018 Improve answer, add missing patternProperties, add new (since original answer) option propertyNames.

Do not understand this type definition in a valid JSON Schema

For the definitions of Cats and Dogs in:
{
"Boxes": {
"type":"object",
"properties": {
"Cats": {"type":["integer","null"]},
"Dogs": {"type":["integer","null"]}
}
}
}
What restraints does "type": [ "integer", "null" ] impose?
The following JSON validates against this schema: { "Boxes": { "Cats": [2, 3, 4, null, "hi"] } }. Since Cats contains an array which in turn contains ints, strings and null, I would have assumed that the validation would have failed.
Firstly, if you want your data to have a top-level property named "Boxes", then you need to define the top-level data to be an object with that property, e.g.
{
"type": "object",
"properties": {
"Boxes": {
"type":"object",
"properties": {
"Cats": {"type":["integer","null"]},
"Dogs": {"type":["integer","null"]}
}
}
}
}
With the schema you've written, the top-level "Boxes" is ignored because it's not a keyword, so the schema effectively has no constraints at all.
If you used the above construction, then the "Cats" and "Dogs" properties would be constrained to be either an integer or null.
Arrays would not be allowed - if you want an array then you should define "type":"array" for these properties and then constrain the array items using items.

JSON Schema - matching based on array inclusion

I have the following simple JSON schema that does the regular expression match based on the content field of my data:
{
"$schema":"http://json-schema.org/schema#",
"allOf":[
{
"properties":{
"content":{
"pattern":"some_regex"
}
}
}
}
It successfully matches the following data:
{
"content": "some_regex"
}
Now lets say I want to add a list of UUIDs to ignore to my data:
{
"content": "some_regex",
"ignoreIds" ["123", "456"]
}
The problem arises when I want to modify my schema not to match when a given value is present in the list of ignoreIds:
Here is my failed attempt:
{
  "$schema": "http://json-schema.org/schema#",
  "allOf": [{
    "properties": {
      "content": {
        "pattern": "some_regex"
      }
    }
  }, {
    "properties": {
      "ignoreIds": {
        "not": {
          // how do I say 'do not match if "123" is in the ignoreIds array'????
        }
      }
    }
  }]
}
Any help will be appreciated!
your JSON schema for the ignoreIds has to be:
"ignoreIds": {
"type": "array",
"items": {
"type": "integer",
"not": {
"enum": [131, 132, whatever numbers you want]
}
}
}
which says
any value in the array ignoreIds matching the not-enum will make the
json invalid
This works of course for an array of strings also:
"ignoreIds": {
"type": "array",
"items": {
"type": "string",
"not": {
"enum": ["131", "132"]
}
}
}
Tested with JSON Schema Lint