I am trying to create JSON schema for below JSON,
{
"messages":{
"bookCreated":{
"default":{
"channels":{
"sqs":{
"enabled":true,
"topic":"sample-topic",
"shares":true
}
}
}
},
"bookCreationInProgress":{
"default":{
"channels":{
"sns":{
"enabled":true,
"topic":"sample-sns",
"shares":true
}
}
}
},
"bookCreationCompleted":{
"default":{
"channels":{
"s3":{
"enabled":true,
"topic":"sample-s3-bucket",
"shares":true
}
}
}
}
}
}
Inside message bookCreated, bookCreationInProgress , bookCreationCompleted similarly we have several dynamic properties. Inside each of these objects default and channel details are mandatory.
And each channel has a set of mandatory attributes.
I browsed internet to create JSON schema for the above json but I couldn't get any reference of how to create json schema for nested map objects.
Since I couldn't able to construct the json schema for very first dynamic object I couldn't able to construct the schema further.
{
"$schema": "app_messages",
"type": "object",
"additionalProperties": true,
"anyOf": [
{
"required": ["messages"]
}
],
"properties": {
"id": {
"type": "string"
}
}
}
It would be really great if somebody would help me to share the pointers of how to handle map of dynamic properties in JSON schema. Any help would be really appreciable.
A good solution use "additionalProperties" as json-object (instead of boolean) combined to "$ref" and "$defs".
A talking example might be:
{
"$schema": "app_messages",
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$ref": "#/$defs/subobj1" },
{ "$ref": "#/$defs/subobj2" }
]
},
"properties": {
"id": { "type": "string" }
},
"$defs": {
"subobj1": {
"type": "object",
"properties": {
"message": { "type": "string" }
...
},
"required": [ "message" ]
},
"subobj2": {
"type": "object",
"properties": {
"message": { "type": "string" }
...
},
"required": [ "message" ]
}
}
}
In this way main object can have "id" properties and all additional properties must match one of sub definition "subobj1" or "subobj2".
Related
I'm stuck on writing a correct json schema for my data.
Condition:
directory is an recursive object with optional property "$meta"
file can be string or object
if file is object it can have optional property "$meta" with oneOf "$data" or "$stringData" not both.
JSON Data:
{
"dir1": {
"dir1A": {},
"dir1B": {
"dir1B01": {
"dir1B0101": {},
"dir1B0102": {},
"dir1B0103": {},
"file1B.txt": {
"$meta": {},
"$data": "ooo",
"$stringData": "Netus et malesuada" // here should failed
}
}
}
},
"dir2": {
"file2.txt": "dolor sit amet" // here should OK but failed
},
"file1.txt": "Lorem Ipsum"
}
Schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/dir.schema.json",
"type": "object",
"patternProperties": {
"^[^\\/?%*:|\"<>]+$": { // failed if name consist of invalid chars
"$ref": "#/$defs/directory"
}
},
"additionalProperties": false,
"$defs": {
"file": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"$data": {
"type": "string",
"description": "base64 encoded data"
},
"$stringData": {
"type": "string"
}
},
"oneOf": [
{
"not": {
"anyOf": [
{
"required": [
"$data",
"$stringData"
]
}
]
}
},
{
"allOf": [
{
"not": {
"required": [
"$data"
]
}
},
{
"not": {
"required": [
"$stringData"
]
}
}
]
}
]
}
]
},
"directory": {
"anyOf": [
{
"$ref": "#/$defs/file"
},
{
"type": "object",
"properties": {
"$meta": {
"type": "object",
"additionalProperties": true,
"properties": {
"createdAt": {
"type": "string"
},
"size": {
"type": "integer"
},
}
}
},
"patternProperties": {
"^[^\\/?%*:|\"<>]+$": {
"$ref": "#"
}
}
}
]
}
}
}
Live Demo: https://www.jsonschemavalidator.net/s/HNFtNfRw
Thank you for help
There are a few issues, so let's walk through deriving this schema one step at a time.
Let's start with the object representation of a file. Here's the easy part.
{
"type": "object",
"properties": {
"$meta": { "$ref": "#/$defs/meta" },
"$data": { "type": "string" },
"$stringData": { "type": "string" }
}
}
Then we need to add the assertion that one and only one of $data or $stringData is required. The oneOf keyword can express this cleanly.
"oneOf": [
{ "required": ["$data"] },
{ "required": ["$stringData"] }
]
Only one of the schemas can validate to true. If both properties are present, the schema will fail.
Next, let's define a file can be represented as a string or an object.
{
"anyOf": [
{ "type": "string" },
{ "$ref": "#/$defs/object-file" }
]
}
Notice that we are using anyOf instead of oneOf in this case. anyOf passes validation as soon as one of the schemas is valid. If the first one passes validation, it doesn't need to check the second one. If oneOf is used, the validator needs to check both schemas because oneOf requires that only one of the schemas passes validation and the rest fail. Because one of these schemas is a string and the other is an object, it's impossible for any JSON data to be both a string an object. Therefore, using oneOf only makes the validation less efficient.
That covers files, let's do directories next.
{
"type": "object",
"properties": {
"$meta": { "$ref": "#/$defs/meta" }
},
"patternProperties": {
"^[^\\/?%*:|\"<>]+$": { "$ref": "#/$defs/file-or-directory" }
},
"additionalProperties": false
}
The recursive reference part is pretty simple, but we have a problem with the $meta property. $meta matches the regular expression in patternProperties, so $meta will need to validate against #/$defs/meta and #/$defs/file-or-directory, which is not what you want. What you need is something like an additionalPatternProperties keyword, but since that doesn't exist, you need to change your patternProperties regex to exclude $meta. Something like this, "^[^\\/?%*:|\"<>]+(?<!\\$meta)$".
Now all that's left is a schema to express that something is a file or a directory.
"anyOf": [
{ "$ref": "#/$defs/file" },
{ "$ref": "#/$defs/directory" }
]
Again, we want to use anyOf, but there's a bit more to this than you might notice at first glance. The problem is that something that matches the file schema will also match the directory schema. So, we can't use oneOf and the file schema needs to come first. If the directory schema was first, it would incorrectly validate files as directories. When the file schema comes first, it checks if it's a file first and the false positive that we would get from the directory schema becomes irrelevant.
I'll leave it to you to put the pieces together into a full schema, but leave a comment if you have any issues.
I have a json schema, it has an array, I want to validate all items from the array but the schema only validate the first element, why the schema doesn't validate the rest?
Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"codigoEmpresa": {
"type": "string"
},
"nombreEmpresa": {
"type": "string"
},
"planes": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"codigoPlan": {
"type": "string"
},
"nombrePlan": {
"type": "string"
},
"tipoProducto": {
"type": "integer"
}
},
"required": [
"codigoPlan",
"nombrePlan",
"tipoProducto"
]
}
]
}
},
"required": [
"codigoEmpresa",
"nombreEmpresa",
"planes"
]
}
Invalid json:
{
"codigoEmpresa":"204",
"nombreEmpresa":"Claro",
"planes":[
{
"codigoPlan":"M-PP-Premium-30.03",
"nombrePlan":"Plan Max Premium Libre",
"tipoProducto":1
},
{
"tipoProducto":3
}
]
}
Schema validator:
https://json-schema-validator.herokuapp.com/
The attributes nombrePlan and tipoProducto in second element from the array are required on the json but the schema validator doesn't validate it.
"items": [ { ... } ]
in your schema should be
"items": { ... }
items keyword in this form will apply a single subschema to all elements found in the array.
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!
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" }
}
}
I'm completely new to json and json schema, so I have a question (yet I don't know how much it make sense). Can we create a json schema which is common for similar type of structure. For example:
One single schema can be used to validate following json
JSON:
{
"Team_Table":
[{"Name":"New Zealand", "Match":"Six", "Won":"Six"}]
}
And
{
"Story_Taller":
[{"Story":"No Name", "Chapter":"Don't know"}]
}
Similarities:
Both have only one object in the array
Objects have string value.
Dissimilarities:
Number of properties are different
Keys are different in both
Can we do this?
Maybe this helps you along:
{
"properties": {
"Story_Taller": {
"type": "array",
"maxItems": 1,
"items": {
"properties": {
"Chapter": {
"type": "string"
},
"Story": {
"type": "string"
}
},
"additionalProperties": false
}
},
"Team_Table": {
"type": "array",
"maxItems": 1,
"items": {
"properties": {
"Name": {
"type": "string"
},
"Match": {
"type": "string"
},
"Won": {
"type": "string"
}
},
"additionalProperties": false
}
}
},
"oneOf": [
{
"title": "Story_Taller",
"required": [
"Story_Taller"
]
},
{
"title": "Team_Table",
"required": [
"Team_Table"
]
}
]
}
in (short) words:
in your JSON there must be one property of either "Story_Taller" or "Team_Table" with a maximum of 1 item
"oneOf": [ ... ]
Properties of both arrays are defined by items
"Story_Taller" must have "Chapter" and "Story" and no additional properties.
"Team_Table" must have "Name", "Match", "Won" and no additional properties.
And all of them are defined as strings.