JsonSchema How to use readonly for array - arrays

I read the specification. But, I didn't find any information about how to use the readOnly of Array. And a single readonly property is not enough to cover different scenarios.
An example array schema like below:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/product.schema.json",
"title": "Products",
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
},
"productName": {
"description": "Name of the product",
"type": "string"
},
"price": {
"description": "The price of the product",
"type": "number"
}
}
}
}
Is it possible to achieve the following objectives?
The array is not allowed to add/remove any item of the array. However, it's allowed to update any item of the array.
The array is not allowed to update any item of the array. However, it's allowed to add/remove item of the array. Once an item is added to the array, the only action I can take is "remove".

readOnly is too blunt an instrument to describe those kinds of constraints. However, with a small change, you can express it with JSON Hyper-Schema. You would have to model the individual products and the list of products separately. Unlike readOnly which says what you can't do, links say what you can do. Here's what it would look like for each of the cases you identified.
The array is not allowed to add/remove any item of the array. However, it's allowed to update any item of the array.
{
"$schema": "http://json-schema.org/draft-07/hyper-schema#",
"$id": "http://example.com/product-list.schema.json",
"type": "array",
"items": { "$ref": "product.schema.json" }
}
{
"$schema": "http://json-schema.org/draft-07/hyper-schema#",
"$id": "http://example.com/product.schema.json",
"type": "object",
"properties": {
"productId": { "type": "integer" },
"productName": { "type": "string" },
"price": { "type": "number" }
},
"links": [
{ "rel": "edit", "href": "/product/{productId}" }
]
}
The array is not allowed to update any item of the array. However, it's allowed to add/remove item of the array. Once an item is added to the array, the only action I can take is "remove".
{
"$schema": "http://json-schema.org/draft-07/hyper-schema#",
"$id": "http://example.com/product-list.schema.json",
"type": "array",
"items": { "$ref": "product.schema.json" },
"links": [
{
"rel": "create",
"href": "/products",
"schema": { "$ref": "product-create.schema.json" }
}
]
}
{
"$schema": "http://json-schema.org/draft-07/hyper-schema#",
"$id": "http://example.com/product.schema.json",
"type": "object",
"properties": {
"productId": { "type": "integer" },
"productName": { "type": "string" },
"price": { "type": "number" }
},
"links": [
{ "rel": "delete", "href": "/product/{productId}" }
]
}

Related

JSON Schema: Check the array to validate if a certain block of JSON objects is contained in it

I have a JSON array of arbitrary length. Each item in the array is a nested block of JSON objects, they all have same properties but different values.
I need a JSON schema to check the array if the last block in the array has the values defined in the schema.
How should the scheme be defined so that it only considers the last block in the array and ignores all the blocks before in the array?
My current solution successfully validates the JSON objects if there is only one block in the array. As soon as I have more blocks, it fails because all the others are not valid against my schema - for sure, this corresponds to the expected behaviour.
In my example, the JSON array contains two nested blocks of JSON objects. These differ for the following items:
event.action = "[load|button]"
event.label = "[journey:device-only|submit,journey:device-only]"
type = "[page|track]"
An example for my data are:
[
{
"page": {
"path": "order/checkout/summary",
"language": "en"
},
"cart": {
"ordercase": "neworder",
"product_list": [
{
"name": "Apple iPhone 14 Plus",
"quantity": 1,
"price": 1000
}
]
},
"event": {
"action": "load",
"label": "journey:device-only"
},
"type": "page"
},
{
"page": {
"path": "order/checkout/summary",
"language": "en"
},
"cart": {
"ordercase": "neworder",
"product_list": [
{
"name": "Apple iPhone 14 Plus",
"quantity": 1,
"price": 1000
}
]
},
"event": {
"action": "button",
"label": "submit,journey:device-only",
},
"type": "track"
}
]
And the schema I use which works fine for the second block if the block would be the only one in the array:
{
"type": "array",
"$schema": "http://json-schema.org/draft-07/schema#",
"items": {
"type": "object",
"required": ["event", "page", "type"],
"properties": {
"page": {
"type": "object",
"properties": {
"path": {
"const": "order/checkout/summary"
},
"language": {
"enum": ["de", "fr", "it", "en"]
}
},
"required": ["path", "language"]
},
"event": {
"type": "object",
"additionalProperties": false,
"properties": {
"action": {
"const": "button"
},
"label": {
"type": "string",
"pattern": "^[-_:, a-z0-9]*$",
"allOf": [
{
"type": "string",
"pattern": "^\\S*(?:(submit,|,submit))\\S*$"
},
{
"type": "string",
"pattern": "^\\S*(journey:(?:(device-only|device-plus)))\\S*$"
}
]
}
},
"required": ["action", "label"]
},
"type": {
"enum": ["track", "string"]
}
}
}
}

SchemaForm array conditional

Background
I am making a form using http://schemaform.io/
Setup
I am trying to make an array of objects that a user can make using a form. So, the user can add as many items into the array as they want.
The array of items contains a type, then another field depending on what the type was.
If the user clicks REST, I want it to offer a field called method.
If the user clicks SSH, I want it to offer a field called path.
Code so far
SCHEMA
{
"type": "object",
"title": "Command Asset",
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"commands": {
"type": "array",
"title": "Actions",
"items": {
"type": "object",
"properties": {
"commandType": {
"title": "Command Type",
"type": "string",
"enum": [
"REST",
"SSH"
]
},
"path": {
"title": "Path",
"type": "string"
},
"method": {
"title": "Method",
"type": "string"
}
}
}
}
}
}
FORM
[
{
"type": "help",
"helpvalue": "<h5>Command</h5>"
},
"name",
{
"title":"Command",
"key": "commands",
"items": [
"commands[].commandType",
{
"type": "conditional",
"condition": "modelData.commands[0].commandType=='SSH'",
"items": [
{
"key": "commands[].path"
}
]
},
{
"type": "conditional",
"condition": "modelData.commands[0].commandType=='REST'",
"items": [
{
"key": "commands[].method"
}
]
}
]
}
]
One can test this code here: http://schemaform.io/examples/bootstrap-example.html
Question
As one can see, the code I have now makes all the items' secondary properties (path or method) dependent on the first item in the array's commandType (at [0]), but I want it to depend on the commandType of the corresponding item. So, if item one has commandType of REST, it offers a method field and if item two has a command type of SSH it offers a field of path and so on.
I found an answer.
Replace the [0] with [arrayIndex].
I found it from here: https://github.com/json-schema-form/angular-schema-form/commit/21f6d3ab64435b032456dfe19e03f96b29366320

Angular schema form access Object with Arrays from Form

I have a scenario where i need to display arrays in side a named object like this:
"actions": {
"singleSelection": [
{
"chartable": false,
"label": ""
}
]
}
I have accomplished it with the following schema:
"schema": {
"type": "object",
"title": "smart_report",
"properties": {
"actions": {
"title": "Actions",
"type": "object",
"properties": {
"singleSelection": {
"title": "Action: Single selection",
"type": "array",
"maxItems": 10,
"items": {
"type": "object",
"properties": {
"field": {
"title": "Field name",
"type": "string"
},
"label": {
"title": "Label",
"type": "string",
"description": "Label will be used for column name."
},
"chartable": {
"title": "Chartable",
"type": "boolean"
}
}
}
}
}
}
}
Now am trying to set the 'notitle' flag on 'actions' in from and trying to access the properties of 'actions', but its not working as expected:
{
"key": "actions",
"notitle": true,
"properties": {
"key": "singleSelection",
"notitle": true,
"startEmpty": true
}
},
I still see title for actions as well for 'singleSelection' and 'stratEmpty' is also not set.
If you remove the titles from the schema, as well as using the notitle attribute it should work.
(In case you remove the title, but do not use the notitle attribute, the title will be displayed with the same name as the key).

Using an array inside array

I'm trying to generate a form which will have multiple vehicles and each vehicle should have multiple people inside it.
I tried to do it by using an array inside another array. But for some obscure reasons it's not working.
This is what I want:
http://i.imgur.com/ZB2kCa1.png
This is what I have (so far):
Form:
[
{
"key": "vehicles",
"items": [
"['vehicles'][]['plate-number']",
"['vehicles'][]['color']",
{
"key": "people",
"items": [
"['vehicles'][]['people'][]['name']"
]
}
]
}
]
Schema:
{
"type": "object",
"properties": {
"vehicles": {
"type": "array",
"items": {
"type": "object",
"properties": {
"plate-number": {
"title": "Plate number",
"type": "string"
},
"color": {
"title": "Color",
"type": "string"
},
"people": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {
"type": "string",
"enum": ["dr","jr","sir","mrs","mr","NaN","dj"]
},
"name": {
"title": "Name",
"type": "string"
}
}
}
}
}
}
}
}
}
Edit:
stefankmitph's answer solvers my problem. Thank you!
But something weird is happening: a new object person is added at the same level of vehicles. Also, when I fill a person's information and then delete this person the models is not updated.
The schema you provide does not add a property 'gender' (as shown in your picture link). So I took 'title' instead of 'gender':
[
{
"key": "vehicles",
"items": [
"vehicles[].plate-number",
"vehicles[].color", {
"key": "people",
"type": "array",
"title": "People",
"items": [
"vehicles[].people[].name",
"vehicles[].people[].title"
]
}
]
}
]
I hope this is what you're looking for!
Note: Tested with Schema Form Example Page

How to define the min size of array in the json schema

I want to make a schema of json file.It's for an array of products.
The json schema is similar as below:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product set",
"type": "array",
"items": {
"title": "Product",
"type": "object",
"properties": {
"id": {
"description": "The unique identifier for a product",
"type": "number"
},
"name": {
"type": "string"
},
"price": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"dimensions": {
"type": "object",
"properties": {
"length": {"type": "number"},
"width": {"type": "number"},
"height": {"type": "number"}
},
"required": ["length", "width", "height"]
},
"warehouseLocation": {
"description": "Coordinates of the warehouse with the product",
"$ref": "http://json-schema.org/geo"
}
},
"required": ["id", "name", "price"]
}
}
The array should at least one item in it. How can I define the minimum of the array?
Do I need to add the minimun defination?
To set the minimum # of item in an array, use the "minItems".
See:
https://datatracker.ietf.org/doc/html/draft-fge-json-schema-validation-00#section-5.3.3
and
http://jsonary.com/documentation/json-schema/?section=keywords/Array%20validation
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
...
"tags": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"maxItems": 4,
"uniqueItems": true
}
},
"required": ["id", "name", "price"]
}
It looks like draft v4 permits what you are looking for. From http://json-schema.org/example1.html:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
...
"tags": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
"required": ["id", "name", "price"]
}
Notice that the "tags" property is defined as an array, with a minimum number of items (1).
I suppose no, at least looking to working draft the minimum is applied only for numeric values, not arrays.
5.1. Validation keywords for numeric instances (number and integer)
...
5.1.3. minimum and exclusiveMinimum
So you should be good with min/maxItems for arrays.

Resources