JSON schema - objects with same datatype - json

I generated the following JSON:
{
"someString" : "example",
"obj1" : {
"opt1" : 1,
"opt2" : 1,
"opt3" : "aaa"
},
"obj2" : {
"opt1" : 55,
"opt2" : 55,
"opt3" : "bbb"
}
}
and there will be more of objects(obj1, obj2, obj3, obj4, ...) with same data type (opt1, opt2, opt3)
now I want to create schema for this but i don't know how to combine all this objects in schema.
EDIT:
I created schema:
root: {
"type" : "object",
"oneOf" : [
{
"properties" : {
"someString" : { "type" : "string" }
},
"patternProperties" : { "^.*$" : { "$ref" : "./schemas/myPatternProperties.json#" } },
"additionalProperties" : false }
}
]
}
and myPatternProperties.json looks:
{
"type" : "object",
"properties" : {
"opt1" : { "type" : "number" },
"opt2" : { "type" : "number" },
"opt3" : { "type" : "string" },
}
"required" : [ "opt1", "opt2", "opt3" ]
}
Is there anything wrong because, my generated JSON is still not recognized as this schema type.

As I understand your problem is to describe object with a lot of properties with the same type and some naming rules. To solve that you must specify patternProperties section
{
"patternProperties": {
"^(/[^/]+)+$": { "$ref": "http://some.site.somewhere/entry-schema#" }
}
that construction specify pattern to match for properties. Example how to use patternProperties Read more at specification
UPDATE
Actually full scheme must be something like that
{
"$schema": "http://json-schema.org/draft-06/schema#",
"type": "object",
"properties": {
"someString": {
"type": "string"
}
},
"patternProperties": {
"^obj([0-9]+)$": {
"$ref": "#/definitions/objEntity"
}
},
"additionalProperties": false,
"required": [ "someString" ],
"definitions": {
"objEntity": {
"type": "object",
"properties": {
"opt1": { "type": "number" },
"opt2": { "type": "number" },
"opt3": { "type": "string" }
},
"required": ["opt1", "opt2", "opt3"]
}
}
}
Of course you can split that scheme to more than 1 file, and change links to type definitions.

Related

How to validate the json against a complex json schema which has multi level of references

I have a json schema as follows
{
"$id": "https://example.com/arrays.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "A representation of a person, company, organization, or place",
"type": "object",
"properties": {
"fruits": {
"type": "array",
"items": {
"type": "string"
}
},
"vegetables": {
"type": "array",
"items": { "$ref": "#/$defs/veggie" }
}
},
"required" : ["fruits", "vegetables"],
"$defs": {
"veggie": {
"type": "object",
"required": [ "veggieName", "veggieLike", "cropLocation"],
"properties": {
"veggieName": {
"type": "string",
},
"veggieLike": {
"type": "boolean",
},
"cropLocation" : {
"type" : "object",
"items" :{ "$ref" : "#/$defs/location"}
}
}
},
"location" : {
"type" : "object",
"required" : ["country", "state"],
"properties" : {
"country" : {
"type": "string"
},
"state" : {
"type": "string"
}
}
}
}
}
When I give data as follows I am expecting error that cropLocation doesnt have state and country prperty. but it validates as success against that schema. How to define schema with multilevel complex objects.
"fruits": [ "apple", "orange", "pear" ],
"vegetables": [
{
"veggieName" : "carrot",
"veggieLike": true,
"cropLocation" : {}
},
{
"veggieName": "broccoli",
"veggieLike": false,
"cropLocation" : {}
}
]
}
I tried variuos ways to restrucutre the json schema, but is not working
The error is here:
"items" :{ "$ref" : "#/$defs/location"}
"cropLocation" is an object, but items is a keyword that only applies to arrays. Simply remove the items keyword and make the $ref a sibling to "type": "object".

Json schema validator, how to validate if key is not static

I am trying to validate this specific schema:
{
"messages": [
{
"name": "test msg",
"id": "0x100",
"signals": {
"0": {"name": "Engine RPM", "bit_length": 16},
"16": {"name": "Gear", "bit_length": 3},
"19": {"name": "Battery Voltage", "bit_length": 5}
}
}
]
}
I am using the python from jsonschema import Draft4Validator to validate this schema... however I am not sure how to continue.
This is my current schema validation so far:
{
"$schema" : "https://json-schema.org/schema#",
"type" : "object",
"properties" :
{
"messages" :
{
"type" : "array",
"items" :
{
"properties" :
{
"name" :
{
"type" : "string"
},
"id" :
{
"type" : "string"
},
"signals" :
{
"type" : "object"
},
"properties" :
{
}
},
"required": ["name", "id", "signals"]
}
}
}
}
The problem I am facing is I am not sure how to deal with the objects that are in the "signals" key as they start with a string and are NOT consistent ("0", "16", "19")... How could I go about validating this by ensuring the type is always a string, disregarding whether or not the string is consistent.
Thanks to all of those who reply in advance.
I was able to accomplish this by doing the following:
{
"$schema" : "https://json-schema.org/schema#",
"type" : "object",
"properties" :
{
"messages" :
{
"type" : "array",
"items" :
{
"properties" :
{
"name" :
{
"type" : "string"
},
"id" :
{
"type" : "string"
},
"signals" :
{
"type" : "object"
},
"properties" :
{
"start_bit" :
{
"type" : "object",
"properties" :
{
"name" :
{
"type" : "string"
},
"bit_length" :
{
"type" : "string"
},
"factor" :
{
"type" : "string"
},
"offset" :
{
"type" : "string"
}
},
"required" : ["name", "bit_length", "factor", "offset"]
}
}
},
"required": ["name", "id", "signals"]
}
}
}
}
To "avoid" having to keep the string consistent, in the validator file, I can put any string (obviously it makes more sense to name the string what is represents, in my case "start_bit") and then by NOT having it be required.

Schema Draft v7 if statement is not informing error in detail

I'm trying to validate a required property with if statement in JsonSchema, but it isn't informing me the property's error in detail.
The validation has been made correctly, but the error don't specify the property and which validation failed.
It works for required properties in the root level of an object, but when I specify a required property inside an object, it just warn that the json doesn't match and specify the then or else schema's path.
Schema example:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"name",
"partners"
],
"properties": {
"partners": {
"type": "array",
"items": {
"type": "object",
"if": {
"properties": {
"juridical": {
"type": "object"
},
"natural": {
"type": "null"
}
}
},
"then": {
"properties": {
"juridical": {
"required": [ "tradeName" ],
"properties": {
"tradeName": {
"type": "string"
}
}
}
}
},
"else": {
"properties": {
"natural": {
"required": ["name"],
"properties": {
"name": {
"type": "string"
}
}
}
}
}
}
}
}
}
Json example:
{
"name": "Joao",
"partners": [
{
"juridical": null,
"natural": {
}
},
{
"juridical": {
"tradeName": ""
},
"natural": null
}
]
}
It should warns that the first partner have the "name" required (Required properties are missing from object: name.), instead it only tell me: JSON does not match schema from 'else'..
With a simple schema like this it works as expected:
Schema example:
{
"if": { "properties": { "power": { "minimum": 9000 } } },
"then": { "required": [ "disbelief" ] },
"else": { "required": [ "confidence" ] }
}
Json example:
{ "power": 10000 }
I'm using JsonSchemaValidator.net to verify the results.
Basically, JSON document either validates against JSON schema or not. This logic goes down through all sub-schemas and conditionals.
The content of error messages depends on specific implementation of JSON Schema validator. The one you use comes from a specific provider. As pointed by Relequestal, you cannot expect specific type of error message handling from specific implementation, unless it's what the provider documentation describes.
How about filing a suggestion to authors of the validator you use about extending messages for if-then-else case, feeding in your case?
Alternative approach: As I understand, your goal is to get as much specific error information as possible with this specific validator. It is what it is, so an alternative schema might fit the goal. As JSON Schema itself is a JSON document, thus you may consider a workaround by naming nodes in Schema in some consistent manner and using one of logical operators ("anyOf" (logical OR), "allOf" (logical AND), "oneOf" (logical XOR) ) instead of if-then-else.
Please note: schema based validator, in case of "allOf", "anyOf", "oneOf" is expected to run through all schemas until the logical condition is satisfied.
"allOf" - will check always if JSON doc validates against all schemas
(AND)
"anyOf" - will check if JSON doc validates at least against 1 schema
(OR, so some validator implementations might stop checking after
first positive result as it's sufficient to evaluate check against
"anyOf" to true),
"oneOf" - will check always if JSON doc validates exactly against
one of enlisted schemas by checking against all of them (XOR)
(see: https://json-schema.org/draft-07/json-schema-validation.html#rfc.section.6.7.1 )
Thus if validated instance doesn't match schemas in above cases, the validator implementation may produce some 'false positives' in terms of error messages, as it will enlist issues encountered vs all schemas. It simply can't read our minds and guess what we meant by providing specific JSON doc, so it throws all on us to judge and decide.
One of many solutions could be to define variants of "juridical" and "natural" and combine them logically into schemas as in your case it seems you expect:
either juridical is an object (+relevant constraints) AND natural is not an object or juridical is not an object and natural is an object
(+relevant constraints).
Alternative schema (please note the "examples" section containing some test JSON documents):
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"name",
"partners"
],
"properties": {
"partners": {
"type": "array",
"items": {
"type": "object",
"anyOf" : [
{"$ref" : "#/definitions/juridical-is-object-and-natural-is-null"},
{"$ref" : "#/definitions/juridical-is-not-an-object-and-natural-is-an-object"}
],
"required" : ["natural","juridical"]
}
}
},
"examples" : [
{
"name": "Joao",
"partners": [
{
"juridical": null,
"natural": {
}
},
{
"juridical": {
"tradeName": ""
},
"natural": null
}
]
},
{
"name": "Joao",
"partners": [
{
"juridical": null,
"natural": {
"name" : ""
}
},
{
"juridical": {
"tradeName": ""
},
"natural": null
}
]
},
{
"name": "Joao",
"partners": [
{
"juridical": null,
"natural": {
}
},
{
"juridical": {
"tradeName": ""
},
"natural": null
},
{
"juridical" : [],
"natural" : {}
}
]
}
],
"definitions" : {
"natural" : {
"is-object" : {
"type" : "object",
"required": ["name"],
"properties": {
"name": {
"type": "string"
}
}
},
"is-not-an-object" : {
"not" : { "type" : "object" }
},
},
"juridical" : {
"is-object" : {
"type" : "object",
"required": ["tradeName"],
"properties": {
"name": {
"type": "string"
}
}
},
"is-not-an-object" : {
"not" : { "type" : "object" }
},
},
"juridical-is-object-and-natural-is-null" : {
"properties" : {
"natural" : {"$ref" : "#/definitions/natural/is-not-an-object"},
"juridical" : {"$ref" : "#/definitions/juridical/is-object"}
},
},
"juridical-is-not-an-object-and-natural-is-an-object" : {
"properties" : {
"natural" : {"$ref" : "#/definitions/natural/is-object"},
"juridical" : {"$ref" : "#/definitions/juridical/is-not-an-object"}
}
},
}
}
Notes:
"not" : { schema } error message might be confusing for casual users, but it conforms to the spec: https://json-schema.org/draft-07/json-schema-validation.html#rfc.section.6.7.4
Update
As explained in comments, you are after error details. Given the constraints of the selected tool in terms of if-then-else error details for more complex schemas, did you try to reshape schema using different keywords to trigger as less overhead messages as possible?
Alternative schema 2
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"name",
"partners"
],
"properties": {
"partners": {
"type": "array",
"items" : {
"properties" : {
"natural" : {
"if" : { "type" : "object" },
"then" : { "required" : ["name"] },
"dependencies" : {
"name" : {
"properties" : {
"name" : {"type" : "string"}
}
}
}
},
"juridical" : {
"if" : { "type" : "object" },
"then" : { "required" : ["tradeName"] },
"dependencies" : {
"tradeName" : {
"propertyNames" : {
"enum" : ["tradeName"]
},
"properties" : {
"tradeName" : {"type" : "string"}
}
}
}
}
},
"anyOf" : [
{"$ref" : "#/definitions/natural-is-null-juridical-is-an-object"},
{"$ref" : "#/definitions/natural-is-an-object-juridical-is-null"}
]
}
}
},
"definitions" : {
"natural-is-null-juridical-is-an-object" : {
"properties" : {
"natural" : { "type": "null"},
"juridical" : { "type" : "object"}
}
},
"natural-is-an-object-juridical-is-null" : {
"properties" : {
"natural" : { "type": "object"},
"juridical" : { "type" : "null"}
}
},
},
"examples" : [
{
"name": "Joao",
"partners": [
{
"juridical": null,
"natural": {
}
},
{
"juridical": {
"tradeName": "",
},
"natural": null
},
{
"juridical" : {},
"natural" : {}
},
{
"juridical" : null,
"natural" : null
}
]
},
]
}

For json-schema how can I declare a type for the json

How can I declare multiple schemas and let a validator select one depending on a property?
For example I would like this json to be validated against second schema for type2
{
"id2": 1,
"name": "A green door",
"price": 12.50,
"tags": ["home", "green"],
"schemaToValidate" : "type2"
}
A first schema definition for object of type1:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"required": ["id1"],
"schemaForType" : "type1"
}
A second schema definition for object of type2:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"required": ["id2"],
"schemaForType" : "type2"
}
I tried to find a sample for this at http://json-schema.org/example1.html but didn't realized if is even possible.
It's not possible to have multiple schema depending on a type but there is an alternative: change your example to use oneOf (also simplified to be easier on the schema):
{
"Type2" : {
"id2": 1
}
}
And with a schema that work on one of Type1 and Type2 can be added:
{
"description" : "schema validating Type1 and Type2",
"type" : "object",
"oneOf" : [{
"properties" : {
"Type1" : {
"type": "object",
"properties" : {
"id1" : {
"type" : "integer"
}
},
"additionalProperties": false
}
},
"required" : [ "Type1" ]
}, {
"properties" : {
"Type2" : {
"type": "object",
"properties" : {
"id2" : {
"type" : "integer"
}
},
"additionalProperties" : false
}
},
"required" : ["Type2"]
}
]
}
Another example of AnyOf

support for std::map< std::string, T > in json schema

Is there a standard approach to specifying a property to be a dictionary or map keyed by string with a value type T specified somewhere else in the schema?
For example, suppose you want to model a user's favorite movies where the key type is the name of the movie and the value type is some set of attributes about the movie (year made, budget, gross income, etc.)
I imagine you could model first a MovieDataPair as a type with name property and a value property containing the desired attributes. Then the map would be an array of those. But, then you would need a special unique constraint that ensured any movie name only appeared once.
Is there something in json schema to support this, or a standard pattern used for it?
If not built in support in json schema, what about other schema solutions?
After some study I've come up with the following answer:
The best way to see this in action is to find some examples. It
happens that there are several examples of this in the draft04 schema
itself (definitions, properties, patternProperties,...) and they
usually follow the same pattern.
For example, the definitions property of the draft04 schema defines what
should appear in a schema at the definitions property. Here is the
subschema associated with the definitions property:
"definitions": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
This says the entry at "#/definitions/" must be an object. The fact
that it is a json object means it will have unique keys itself. Now
for the values in the object, that is what additionalProperties is
designed to describe. In this case it says that the value of each
property must itself conform to the root of the schema "#". What this
means is that each value in the definitions property object of a valid json schema
object must also be a schema.
If this were typed like C++ it might look like:
std::map< std::string, Schema > definitions;
Effectively a map with a string key can be thought of as like a json
object with a structured value type. So, to create your own:
std::map< std::string, T >
First define the schema for T. For example:
"definitions" : {
"movie" : {
"properties": {
"title" : { "type" : "string" },
"year_made" : { "type" : "integer" },
"rating" : { "type" : "integer" }
}
}
}
For the value type T stored, decide if you want to allow any
properties, as long as these specified properties are typed as
specified above. If you only want these properties, add
"additionalProperties" : false
"definitions" : {
"movie" : {
"additionalProperties" : false,
"properties": {
"title" : { "type" : "string" },
"year_made" : { "type" : "integer" },
"rating" : { "type" : "integer" }
}
}
}
Also decide if you actually require all of the properties to be
present for the movie to be valid. If so, add a required entry.
"definitions" : {
"movie" : {
"additionalProperties": false,
"required" : [ "title", "year_made", "rating" ],
"properties": {
"title" : { "type" : "string" },
"year_made" : { "type" : "integer" },
"rating" : { "type" : "integer" }
}
},
Now the shape T for movie is defined. Create a definition for
the collection, or map of movies referencing the movie schema
defined as was done by definitions in the draft schema. Note: in
the "movie_map" additionalProperties has a different meaning than
that of "movie". In the case of "movie" it is a boolean false
which indicates no additional properties beyond what is listed in
properties. In the case of "movie_map" it means - if there are
additional properties, they must look like this schema. But,
since no properties have been specified in movie_map it really means
all properties in the object instance must conform to #/definitions/movie. Now all
values in a "movie_map" will look like the defined movie schema.
{
"definitions" : {
"movie" : {
"additionalProperties": false,
"required" : [ "title", "year_made", "rating" ],
"properties": {
"title" : { "type" : "string" },
"year_made" : { "type" : "integer" },
"rating" : { "type" : "integer" }
}
},
"movie_map" : {
"type": "object",
"additionalProperties": { "$ref": "#/definitions/movie" },
"default": {}
}
}
}
Now use the defined schema movie_map somewhere within the schema:
{
"title" : "movie data",
"additionalProperties" : false,
"required" : [ "movies" ],
"properties" : {
"movies" : { "$ref" : "#/definitions/movie_map" }
},
"definitions" : {
"movie" : {
"additionalProperties": false,
"required" : [ "title", "year_made", "rating" ],
"properties": {
"title" : { "type" : "string" },
"year_made" : { "type" : "integer" },
"rating" : { "type" : "integer" }
}
},
"movie_map" : {
"type": "object",
"additionalProperties": { "$ref": "#/definitions/movie" },
"default": {}
}
}
}
Here is a sample object, which can be thought of as a map, of movies
that validates against the schema:
{
"movies" : {
"the mission" : {
"title":"The Mission",
"year_made":1986,
"rating":5
},
"troll 2" : {
"title":"Troll 2",
"year_made":1990,
"rating":2
}
}
}
If I wanted to model a structure for users favorites movies (remind Json Schema is intended for structure validation) I would make something like:
{
"description":"moviesFan",
"properties": [
"favoriteMovies": {
"type":"array",
"uniqueItems":True
"allOf": [{ "$ref": "#/definitions/movie" }]
}
],
"definitions": {
"movie": {
"type": "object",
"properties": {
"yearMade": {}
...
}
}
}
Does it make sense to you?
Here's my way to support for map. Hope to help.
{
"type": "object",
"title": "map data",
"required": [
"map"
],
"properties": {
"sOnePurRecord": {
"title": "map",
"additionalProperties": false,
"properties": {
"mapItem": {
"type": "object",
"maxProperties": 10,
"minProperties": 1,
"patternProperties": {
"^[a-zA-Z0-9]{5,20}$": {
"$ref": "#/definitions/value"
}
},
"additionalProperties": {
"$ref": "#/definitions/value"
}
}
},
"required": [
"mapItem"
]
}
},
"definitions": {
"value": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"id": {
"type": "integer"
}
}
}
}
}