UUIDs as object keys in JSON Schema - json

I am trying to define a JSON Schema for a JSON API that uses UUIDs as their key for a JSON object. What makes it more complex is that it is also a nested object.
Example:
{
"nodes": {
"7059e5ad-fac0-4fda-aa3e-2655d6e60506": {
"type": "Class",
"name": "Supermarket",
"data": {},
"instances": {},
}
}
}
Which has a generated schema like this:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"nodes": {
"type": "object",
"properties": {
"7059e5ad-fac0-4fda-aa3e-2655d6e60506": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"name": {
"type": "string"
},
"data": {
"type": "object"
},
"instances": {
"type": "object"
}
}
}
}
}
}
}
Is there a way I can make a schema where there are no UUIDs values in the schema because these values can be anything?

You can leverage the existing uuid format definition, in draft2019-09 and later:
"propertyNames": {
"format": "uuid"
},
"additionalProperties": {
.. definition of the values that go under the uuid properties ..
}

Replace properties with patternProperties, and your UUID with the following regular expression.
^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$
The patternProperties keyword is like the properties keyword, but you can use a regular expression for the key. This works in draft-04 JSON Schema, but it's highly recommended to use a newer version of JSON Schema if you can.
This regex was borrowed, but I'm reasonably confident it is for a UUID.

Related

JSON schema equivalent of XML schema keyref

I am trying to create a JSON schema for data that looks like this:
{
"equipments": {
"A": {},
"B": {}
},
"work": [
{
"equipment": "A"
}
]
}
The schema I currently have is this:
{
"$id": "example",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"equipments":{
"type": "object",
"additionalProperties": true
},
"work": {
"type": "array",
"items": {
"type": "object",
"properties": {
"equipment": {
"type": "string",
}
}
}
}
}
}
In the equipments object different pieces of equipment are configured. These should then be referenced from items in the work array. In an XML schema I would do this with a keyref but I cannot find any equivalent for JSON schemas. Is there an equivalent or is this just not possible with JSON schemas?
It's not currently possible to validate relational data in JSON Schema.
There is a JSON Schema Vocabulary created to reference instance data, but I don't think that would do what you're looking for either.
There was an effort to define a Vocabulary for databases, but that has stalled.

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.

How to define an object with a veriable name in JSON Schema?

I want to create a JSON schema for this JSON "pseudo-code" example:
{
"xyz": {
"$something": {
"property_a": "...",
"property_b": "...",
"property_c": "..."
}
}
}
$something can be one of the following strings: foo, bar, or buz. My current schema looks like this:
{
"xyz": {
"id": "xyz",
"type": "object",
"properties": {
"foo": {
"id": "foo",
"type": "object",
"additionalProperties": false,
"required": ["property_a"],
"properties": {
"property_a": {
"id": "property_a",
"type": "string"
},
"property_b": {
"id": "property_b",
"type": "string"
},
"property_c": {
"id": "property_a",
"type": "string"
}
}
},
"bar": {
... copy&paste foo
},
"buz": {
... copy&paste foo
}
}
}
}
It's working, but it's a lot duplicated code. So I'm looking for a more elegant way for implementing it.
How to define a list of values (lie enum) allowed as name for a property in JSON Schema?
patternProperties works like properties, except the keys of the object are regular expressions.
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.5
An example from the Understanding JSON Schema site
{
"type": "object",
"patternProperties": {
"^S_": { "type": "string" },
"^I_": { "type": "integer" }
},
"additionalProperties": false
}
In this example, any additional properties whose names start with the
prefix S_ must be strings, and any with the prefix I_ must be
integers. Any properties explicitly defined in the properties keyword
are also accepted, and any additional properties that do not match
either regular expression are forbidden.

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

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" }
]
}
}

How to tell JSON schema validator to pick schema from property value?

For example a schema for a file system, directory contains a list of files. The schema consists of the specification of file, next a sub type "image" and another one "text".
At the bottom there is the main directory schema. Directory has a property content which is an array of items that should be sub types of file.
Basically what I am looking for is a way to tell the validator to look up the value of a "$ref" from a property in the json object being validated.
Example json:
{
"name":"A directory",
"content":[
{
"fileType":"http://x.y.z/fs-schema.json#definitions/image",
"name":"an-image.png",
"width":1024,
"height":800
}
{
"fileType":"http://x.y.z/fs-schema.json#definitions/text",
"name":"readme.txt",
"lineCount":101
}
{
"fileType":"http://x.y.z/extended-fs-schema-video.json",
"name":"demo.mp4",
"hd":true
}
]
}
The "pseudo" Schema note that "image" and "text" definitions are included in the same schema but they might be defined elsewhere
{
"id": "http://x.y.z/fs-schema.json",
"definitions": {
"file": {
"type": "object",
"properties": {
"name": { "type": "string" },
"fileType": {
"type": "string",
"format": "uri"
}
}
},
"image": {
"allOf": [
{ "$ref": "#definitions/file" },
{
"properties": {
"width": { "type": "integer" },
"height": { "type": "integer"}
}
}
]
},
"text": {
"allOf": [
{ "$ref": "#definitions/file" },
{ "properties": { "lineCount": { "type": "integer"}}}
]
}
},
"type": "object",
"properties": {
"name": { "type": "string"},
"content": {
"type": "array",
"items": {
"allOf": [
{ "$ref": "#definitions/file" },
{ *"$refFromProperty"*: "fileType" } // the magic thing
]
}
}
}
}
The validation parts of JSON Schema alone cannot do this - it represents a fixed structure. What you want requires resolving/referencing schemas at validation-time.
However, you can express this using JSON Hyper-Schema, and a rel="describedby" link:
{
"title": "Directory entry",
"type": "object",
"properties": {
"fileType": {"type": "string", "format": "uri"}
},
"links": [{
"rel": "describedby",
"href": "{+fileType}"
}]
}
So here, it takes the value from "fileType" and uses it to calculate a link with relation "describedby" - which means "the schema at this location also describes the current data".
The problem is that most validators do not take any notice of any links (including "describedby" ones). You need to find a "hyper-validator" that does.
UPDATE: the tv4 library has added this as a feature
I think cloudfeet answer is a valid solution. You could also use the same approach described here.
You would have a file object type which could be "anyOf" all the subtypes you want to define. You would use an enum in order to be able to reference and validate against each of the subtypes.
If the sub-types schemas are in the same Json-Schema file you don't need to reference the uri explicitly with the "$ref". A correct draft4 validator will find the enum value and will try to validate against that "subschema" in the Json-Schema tree.
In draft5 (in progress) a "switch" statement has been proposed, which will allow to express alternatives in a more explicit way.