Recursive JSON Schema - json

I'm trying to create proper JSON Schema for menu with sub-menus.
So I should define an array from item which should contain three items.
1 Display name, 2 URL and Children (which should be an array of object with the same structure)
At this time I've got this:
{
"type": "array",
"additionalProperties": false, // have no idea what is this for :)
"items": {
"type": "object",
"additionalProperties": false, // have no idea what is this for :)
"description": "MenuLink",
"id": "menuLink",
"properties": {
"display_name": {
"type": "string",
"title": "Link display name",
"minLength": 2
},
"url": {
"type": "string",
"title": "URL address",
"minLength": 2
},
"children": {
"type": "array",
"title": "Childrens",
"additionalItems": false, // have no idea what is this for :)
"items": {
"$ref": "menuLink"
}
}
},
"required": [
"display_name",
"url"
]
}
}
The problem is that it valid only for the first level of the menu
Any help will be appreciated

additionalProperties in arrays does nothing, it is simply ignored. For object it doesn't allow any other properties that are not defined in 'properties'
This schema may or may not work depending on the validator. Reference resolution is the trickiest subject that very few validators do correctly. Check out this: https://github.com/ebdrup/json-schema-benchmark
The more traditional approach to creating what you want:
{
"definitions": {
"menuLink": {
"type": "object",
"additionalProperties": false,
"properties": {
"display_name": {
"type": "string",
"title": "Link display name",
"minLength": 2
},
"url": {
"type": "string",
"title": "URL address",
"minLength": 2
},
"children": {
"type": "array",
"title": "Childrens",
"items": { "$ref": "#/definitions/menuLink" }
}
},
"required": [ "display_name", "url" ]
}
},
"type": "array",
"items": { "$ref": "#/definitions/menuLink" }
}

use definitions and $ref.
Use this online json/schema editor to check your schema visually.
Paste the schema code to the Schema area and click Update Schema.
editor screenshot:
------------------>>>
schema code:
{
"definitions": {
"MenuItem": {
"title": "MenuItem",
"properties": {
"display_name": {
"type": "string",
"title": "Link display name",
"minLength": 2
},
"url": {
"type": "string",
"title": "URL address",
"minLength": 2
},
"children": {
"type": "array",
"title": "Children",
"items": {
"$ref": "#/definitions/MenuItem"
}
}
}
}
},
"title": "MenuItems",
"type": "array",
"items": {
"$ref": "#/definitions/MenuItem"
}
}

Related

Restrict enum values defined in a separate JSONschema

I have a simple enums only schema separately to the payload schema say like this
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "demo::common::Husbandry",
"properties": {
"Anilmals": {
"$ref": "#/definitions/Anilmals"
},
"Breeds": {
"$ref": "#/definitions/Breeds"
}
},
"definitions": {
"Anilmals": {
"type": "string",
"description": "Any animal",
"minLength": 1,
"maxLength": 30,
"enum": [
"Dog",
"Cat",
"Bear",
"Human"
]
},
"Breeds": {
"type": "string",
"description": "Any Breed",
"minLength": 1,
"maxLength": 30,
"enum": [
"Poodle",
"Cheshire",
"Polar",
"Trump"
]
}
}
}
If I/payload producer was to send out a stricter schema over this to express and code additional rules without violating the original schema, Example - When Animal chosen was "Cat" they can only choose "Cheshire" as a Breed and so on how would I code the stricter schema? Note the original schema is not changeable and readonly. I may need to use anyOf or oneOf but can't seem to find a good example.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"ReferenceToLocalSchema": {
"$ref": "#/definitions/LocalType"
},
"ReferenceToExternalSchema": {
"$ref": "masterh-husbandry.json#/properties"
}
},
"definitions": {
"LocalType": {
"type": "object",
"additionalProperties": false,
"properties": {
"no-write": {
"type": "boolean",
"default": false
}
}
}
}
}

JSON schema with data containing external data

Say I have a JSON object which looks like this:
{
"identifier": "carModels",
"friendlyName": "Car Models",
"dataType": "int",
"isRequired": false,
"format": null,
"selectableOptions": {
"url": "http://some-service-resources/carmodels",
"displayPropertyName": "value1",
"valuePropertyName": "name",
"selectMode": "single"
}
}
I can easily use an online tool to create the JSON schema which looks like this:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"identifier": {
"type": "string"
},
"friendlyName": {
"type": "string"
},
"dataType": {
"type": "string"
},
"isRequired": {
"type": "boolean"
},
"format": {
"type": "null"
},
"selectableOptions": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"displayPropertyName": {
"type": "string"
},
"valuePropertyName": {
"type": "string"
},
"selectMode": {
"type": "string"
}
},
"required": [
"url",
"displayPropertyName",
"valuePropertyName",
"selectMode"
]
}
},
"required": [
"identifier",
"friendlyName",
"dataType",
"isRequired",
"format",
"selectableOptions"
]
}
This schema, and data, however, does not give the full picture. It does not contain a definition of car models, retrievable from http://some-service-resources/carmodel, nor does it contain the possible options for selectableOptions.selectMode, which could be single or multiple.
How does one handle this?

Can maxItems/minItems be used with a $ref in a JSON schema

Given a JSON schema with the following in the definitions section:
"phoneNumber": {
"type": "object",
"properties": {
"countryCode": {
"type": "number"
},
"areaCode": {
"type": "number"
},
"number": {
"type": "number"
},
"extension": {
"type": "number"
},
"service": {
"type": "string",
"enum": ["Voice", "Fax", "Data"]
},
"class": {
"type": "string",
"enum": ["Switchboard", "Direct", "PA", "Mobile"]
}
}
}
If I want to include phoneNumber elsewhere using a $ref and want the JSON to validate if it contains multiple occurrences of phoneNumber, can I use maxItems/minItems:
"person": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"phoneNumber": {
"$ref": "#/definitions/phoneNumber"
//can I use maxItems/minItems here?
}
}
}
Can I use maxItems and minItems here, or would I have to do something like this below for it to validate:
"phoneNumber": {
"allOf": { "$ref": "#/definitions/phoneNumber" },
"maxItems": 4
}
$ref must stand alone. The option you identified using allOf is the best way to do it.
Any members other than "$ref" in a JSON Reference object SHALL be ignored.
https://datatracker.ietf.org/doc/html/draft-pbryan-zyp-json-ref-03#section-3

In json schema, how to chain definitions?

I'm trying to build a json schema with "chained" definition.
For the given schema :
{
"$schema": "http://json-schema.org/schema#",
"id": "http://toto/filter-schema#",
"title": "filter schema definition",
"type": "object",
"description": "filter data",
"definitions": {
"timeFilters": {
"type": "object",
"oneOf": [
{
"properties": {
"since": {
"type": "string",
"format": "date-time",
"description": "sends only items that have been modified AFTER this"
}
},
"additionalProperties": false,
"required": [
"since"
]
},
{
"properties": {
"from": {
"type": "string",
"format": "date-time",
"description": "return only data that have a validity date AFTER this"
},
"to": {
"type": "string",
"format": "date-time",
"description": "return only data that have a validity date BEFORE this"
}
},
"additionalProperties": false,
"required": [
"from",
"to"
]
}
]
},
"objectFilters": {
"type": "object",
"properties": {
"objectFilters": {
"type": "array",
"description": "the array of object filter",
"minItems": 1,
"uniqueItems": true,
"items": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"targetClass": {
"type": "string",
"description": "the target class"
},
"targetAttribute": {
"type": "string",
"description": "the target attribute"
},
"test": {
"type": "string",
"description": "the test on the attribute value"
}
}
}
]
}
},
"additionalProperties": false
}
},
"anyOf": [
{
"additionalProperties": false
},
{
"$ref": "#/definitions/timeFilters",
"additionalProperties": false
},
{
"$ref": "#/definitions/objectFilters",
"additionalProperties": false
}
]
}
this schema is validating
{
"since": "2016-02-17T01:02:03.1Z"
}
and
{
"from": "2016-02-17T01:02:03.1Z",
"to": "2016-02-17T01:02:03.1Z",
}
and
{
"objectFilters": [
{
"targetClass": "test",
"targetAttribute": "test",
"test": "test"
}
]
}
and even
{}
but not
{
"since": "2016-02-17T01:02:03.1Z",
"objectFilters": [
{
"targetClass": "test",
"targetAttribute": "test",
"test": "test"
}
]
}
How can make it validating the last json ?
I have tried to add a new definition to the "anyOf", something like this :
{
"$ref": "#/definitions/timeFilters",
"$ref": "#/definitions/objectFilters",
"additionalProperties": false
}
but it does not work.
I use the draft v4.
EDIT :
Also tried
{
"$ref": "#/definitions/timeFilters",
"additionalProperties": {
"$ref": "#/definitions/objectFilters",
"additionalProperties": false
}
}
not working either
The behavior of additionalProperties can get confusing when combining schemas. I suggest a different approach. It's easier to declare all your properties upfront and then declare the required properties constraints separately.
The dependencies keyword works well in this case.
http://json-schema.org/latest/json-schema-validation.html#anchor70
{
"$schema": "http://json-schema.org/schema#",
"id": "http://toto/filter-schema#",
"title": "filter schema definition",
"description": "filter data",
"type": "object",
"properties": {
"since": {
"type": "string",
"format": "date-time",
"description": "sends only items that have been modified AFTER this"
},
"from": {
"type": "string",
"format": "date-time",
"description": "return only data that have a validity date AFTER this"
},
"to": {
"type": "string",
"format": "date-time",
"description": "return only data that have a validity date BEFORE this"
},
"objectFilters": {
"type": "array",
"description": "the array of object filter",
"minItems": 1,
"uniqueItems": true,
"items": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"targetClass": {
"type": "string",
"description": "the target class"
},
"targetAttribute": {
"type": "string",
"description": "the target attribute"
},
"test": {
"type": "string",
"description": "the test on the attribute value"
}
}
}
]
}
},
"additionalProperties": false,
"dependencies": {
"since": {
"not": { "required": ["from"] }
},
"from": ["to"],
"to": ["from"]
}
}

Validate property against another with JSON Schema

In the model below, "category_id" property should be required only if "detail" array is empty.
If "detail" array is not empty, "category_id" property is not required.
How can I do this with JSON Schema?
{
"description": "Expense model validation.",
"type": "object",
"properties": {
"description": {
"type": "string"
},
"category_id": {
"type": "string"
},
"detail": {
"type": "array",
"items": {
"description": "Expense detail",
"type": "object",
"properties": {
"description": {
"type": "string"
}
},
"required": [ "description" ]
}
}
},
"required": [ "description", "category_id" ]
}
You can use anyOf to check that either category_id is present, or detail is present and has at least one item.
{
"description": "Expense model validation.",
"type": "object",
"properties": {
"description": { "type": "string" },
"category_id": { "type": "string" },
"detail": {
"type": "array",
"items": {
"description": "Expense detail",
"type": "object",
"properties": {
"description": { "type": "string" }
},
"required": ["description"]
}
}
},
"required": ["description"],
"anyOf": [
{ "required": ["category_id"] },
{
"properties": {
"detail": { "minItems": 1 }
},
"required": ["detail"]
}
]
}