JSON schema - possible to reference multiple schemas from one object? - json

Below is an extract from my JSON schema.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"images": {
"type": "array",
"items": { "$ref": "#/definitions/bits" },
}
},
"definitions": {
"identifier": {
"type": "string"
},
"bits": {
"type": "integer",
"enum": [
8,
16,
32
]
}
}
}
As specified, I believe an array of images, where each element consists of a string identifier and an integer whose value can be 8, 16 or 32, would be considered valid JSON data.
This is fine for some of my JSON data.
But what if I want to further constrain the schema such that the integer value can only be 32? How would I do that while still allowing some JSON data to be valid against the original schema?
Is it possible, for example, to reference two schemas in one object, E.g. something like:
items": { "$ref": "#/definitions/bits" AND "$ref": "#/definitions/otherSchema"}

You can use allOf to validate against multiple schemas.
{
"items": {
"allOf": [
{ "$ref": "#/definitions/bits" },
{ "$ref": "#/definitions/otherSchema" }
]
}
}

Related

Limit type of JsonArray elements to the same type, but not limit types

We have the following JSON:
{ "someName" : [1,2,3,4,5] }
or
{ "someName" : ["one","two","three"] }
We want to draft a JSON Schema following the OpenAPI 3.x specification. Our constraint: an array element can be integer or string, but all array elements must be the same type. Our schema looks like this:
{
"type": "array",
"items": {
"oneOf": [
{"type": "string"},
{"type": "integer"}
]
}
}
This does limit the data type inside the array, but still allows to mix strings and integers in one array which we need to avoid.
{"someName" : 1, "two", "three", 4}
We looked at this question, but it didn't address consistent data type
Is there a way in OpenAPI Schema to enforce uniqueness per array?
You need to bring the oneOf up a level. Also, anyOf is a better choice in this situation. The result is the same in this case, but anyOf is more efficient.
{
"type": "array",
"anyOf": [
{ "items": { "type": "string" } },
{ "items": { "type": "integer" } },
]
}
Edit: In response to comment ...
To work around the bug, you can try pulling the type into the anyOf. The duplication is unfortunate an will make the schema less efficient, but it will probably help get around the bug.
{
"anyOf": [
{
"type": "array",
"items": { "type": "string" }
},
{
"type": "array",
"items": { "type": "integer" }
}
]
}

How to create JSON schema for validate if given field of type string contains value from given string array

I need to create JSON Schema (can use any version) to validate the string field that may only contain values from given string array in other field.
MVE Example:
For the "picked" the only valid values are ones specified in "values"
Valid:
{
"values": ["Foo", "Bar", "Baz"],
"picked": "Bar"
}
Invalid:
{
"values": ["Foo", "Bar", "Baz"],
"picked": "NotFromValues"
}
Schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": { "type": "string" }
},
"picked": {
"type": "string"
// How can I validate picked?
}
}
}
What you're wanting isn't supported by json schema out of the box. You'll need some custom logic to do it.
There has been a lot of discussion on the spec repo about it. If you do a search for issues with the $data label, you'll have a lot to read. The short of it is that no one could agree on how it should work. The topic is now all but abandoned.
To address this, I have taken advantage of the 2019-09 (and later) vocabularies feature. I have written a new vocabulary that defines a data keyword to support this kind of behavior. The catch is it's only supported (to my knowledge) in my implementation, JsonSchema.Net, but you could implement it yourself if you're using an implementation that lets you define your own keywords.
For your example, you'll need this:
{
"$schema": "https://gregsdennis.github.io/json-everything/meta/data",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": { "type": "string" }
},
"picked": {
"type": "string",
"data": {
"enum": "#/values"
}
}
}
}
(Note that the $schema value changed.)
This will find the values property at the root of your instance (an array), replace "/values" with that, then evaluate as if the value of data was a schema.
In the end, for your example, you're evaluating against this schema:
{
"$schema": "https://gregsdennis.github.io/json-everything/meta/data",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": { "type": "string" }
},
"picked": {
"type": "string",
"enum": [ "Foo", "Bar", "Baz" ]
}
}
}
but the value of enum comes from the instance.
You can test this at https://json-everything.net/json-schema.

Using multiple anyOf inside oneOf

I wanted to create a schema where I will be having multiple objects inside "oneOf" which will be having many objects in anyOf format where some of the keys can be of required type(this part works)
My schema :-
{
"description": "schema v6",
"type": "object",
"oneOf": [
{
"properties": {
"Speed": {
"items": {
"anyOf": [
{
"$ref": "#/definitions/speed"
},
{
"$ref": "#/definitions/SituationType"
}
]
},
"required": [
"speed"
]
}
},
"additionalProperties": false
}
],
"definitions": {
"speed": {
"description": "Speed",
"type": "integer"
},
"SituationType": {
"type": "string",
"description": "Situation Type",
"enum": [
"Advice",
"Depend"
]
}
}
}
But when I'm trying to verify this schema but i'm able to authenticate some incorrect values like
{
"Speed": {
"speed": "ABC",//required
"SituationType1": "Advisory1" //optional but key needs to be correct
}
}
correct response which i was expecting was
{
"Speed": {
"speed": "1",
"SituationType": "Advise"
}
}
First, you need to set the schema type correctly, otherwise implmentations may assume you're using the latest JSON Schema version (currently draft-7).
So, in your schema root, you need the following:
"$schema": "http://json-schema.org/draft-06/schema#",
Second, items is only applicable if the target is an array.
Currently your schema only checks the following:
If the root object has a property of "Speed", it must have a key of
"speed". The root object must not have any other properties.
And nothing else.
Your use of definitions and how you reference them is probably not what you intended.
It looks like you want Speed to contain speed which must be an integer, and optionaly SituationType which must be a string, limited by enum, and nothing else.
Here's the schema I have based on that, which passes and fails correctly based on your given example data:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"type": "object",
"oneOf": [
{
"properties": {
"Speed": {
"properties":{
"speed": {
"$ref": "#/definitions/speed"
},
"SituationType": {
"$ref": "#/definitions/SituationType"
}
},
"required": [
"speed"
],
"additionalProperties": false
}
},
"additionalProperties": false
}
],
"definitions": {
"speed": {
"description": "Speed",
"type": "integer"
},
"SituationType": {
"type": "string",
"description": "Situation Type",
"enum": [
"Advice",
"Depend"
]
}
}
}
You need to define the properties for Speed, because otherwise you can't prevent additional properties, as additionalProperties is only effected by adjacent an properties key. We are looking to created a new keyword in draft-8 to support this kind of behaviour, but it doesn't look like you need it in your example (Huge Github issue in relation).
Adding additionalProperties false to the Speed schema now prevents other keys in that object.
I SUSPECT that given your question title, there may be more schema at play here, and you've simplified it for this question. If you have a more detailed schema with more complex issues, I'd be happy to help also.

JSON Schema validator with an array of specific objects (different types)

I have the following JSON data that I would like to validate.
[
{ "fieldType": "oneThing" },
{ "fieldType": "anotherThing" },
{ "fieldType": "oneThing" }
]
And my current (non working) schema is:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "array",
"items": {
"oneOf": [
{ "$ref": "#/definitions/oneThing" },
{ "$ref": "#/definitions/anotherThing" }
]
},
"definitions": {
"oneThing": {
"type": "object",
"properties": {
"fieldType": {
"type": "string",
"pattern": "oneThing"
}
},
"required": [
"fieldType"
]
},
"anotherThing": {
"type": "object",
"properties": {
"fieldType": {
"type": "string",
"pattern": "anotherThing"
}
},
"required": [
"fieldType"
]
}
}
}
I'm getting the following error but I fail to see what I'm doing wrong.
[] Object value found, but an array is required
More context: I'm generating a dynamic HTML form based on a JSON configuration. The HTML form will have a specific set of valid field types and the same field type may exist multiple times in the config, thus oneThing appearing more than once in the above sample json.
As it turns out, this had nothing to do with my JSON schema but with how I was calling the library that was parsing the schema.
I'm using https://github.com/justinrainbow/json-schema and was passing the wrong data type to the class. Duh!

How to represent sum/union types in in json schema

I am trying to document an existing use of JSON using json-schema. The system permits the following two possabilities for one of the object attributes.
Either
{
"tracking_number" : 123
}
Or
{
"tracking_number" : [ 123, 124, 125 ]
}
How can I express this using json schema?
Use anyOf to assert that the property must conform to one or another schema.
{
"type": "object",
"properties": {
"tracking_number": {
"anyOf": [
{ "$ref": "#/definitions/tracking_number" },
{ "type": "array", "items": { "$ref": "#/definitions/tracking_number" }
]
},
"definitions": {
"tracking_number": { "type": "integer" }
}
}