Why can't the schema see the required array? - json

I have created a JSON Schema, but when I try to use it to validate another object, the schema fails due to an error, citing:
Message:
Required properties are missing from object: Envelope.
Schema path:
#/required
However, I can clearly see the required array listed inside of the envelope as a sibling to its properties. In every schema I've seen online, this is how is is displayed. I have included a trimmed-down selection of the schema below that still sees the same error. Can anyone tell me why this is failing?
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Envelope": {
"type": "object",
"properties": {
"TP_UNIQUE_NUM": {
"length": 50,
"type": "string"
},
"SENDER_ID": {
"length": 50,
"type": "string"
},
"TRANSMISSION_FORMAT": {
"length": 50,
"type": "string"
},
"RECEIVER_ID": {
"length": 50,
"type": "string"
},
"HEADER": {
"type": "object",
"properties": {
"door": {
"description": "Door at which product associated with ASN is scheduled to be unloaded",
"type": "string",
"mandatory": "Y",
"maxLength": 10
},
"notes": {
"description": "Comments associated with ASN",
"type": "string",
"mandatory": "Y",
"maxLength": 4000
},
"wareHouseReference": {
"description": "Additional notes or reference information for the warehouse",
"type": "string",
"mandatory": "Y",
"maxLength": 100
}
},
"required": [
"wareHouseReference"
]
},
"TP_TRANSMISSION_TYPE": {
"maxLength": 50,
"type": "string"
},
"FILE_NAME": {
"maxLength": 50,
"type": "string"
},
"TRANSMISSION_DATE_TIME": {
"maxLength": 50,
"type": "string"
},
"TRANSACTION_COUNT": {
"maxLength": 50,
"type": "string"
}
}
}
},
"required": [
"Envelope"
]
}

It seems that you are missing a required array within the Envelope object.
You have a required array at the root level object, you also have one within the HEADER object, but not within the Envelope object.
I'm assuming a required array is required for each object type.
EDIT: My assumption is probably wrong, I was able to run your schema at json-schema-validator without an issue using this sample JSON. #Jason Desrosiers comment seems to be right on the money.
{
"Envelope": {
"TP_UNIQUE_NUM": "hello",
"SENDER_ID": "hello",
"TRANSMISSION_FORMAT": "hello",
"RECEIVER_ID": "hello",
"HEADER": {
"door": "hello",
"notes": "hello",
"wareHouseReference": "hello"
},
"TP_TRANSMISSION_TYPE": "hello",
"FILE_NAME": "hello",
"TRANSMISSION_DATE_TIME": "hello",
"TRANSACTION_COUNT": "hello"
}
}

Related

Erroneous successful validation by JSON-schema

The fields in nodes depend on the value of entity. That is, if entity = "pd", then nodes has some fields, while entity = " top " - nodes has completely different fields, despite the fact that they are strictly required. For some reason, the JSON string is accepted by the valid schema, even if there are no fields defined in nodes as required. I already entire head broke, where can be mistake in the most scheme?
JSON-schema:
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/root.json",
"type": "object",
"title": "The Root Schema",
"required": [
"virtual"
],
"properties": {
"virtual": {
"$id": "#/properties/virtual",
"type": "array",
"title": "The Virtual Schema",
"items": {
"$id": "#/properties/virtual/items",
"type": "object",
"title": "The Items Schema",
"required": [
"type",
"path",
"entity",
"nodes"
],
"properties": {
"type": {
"$id": "#/properties/virtual/items/properties/type",
"type": "string",
"title": "The Type Schema",
"default": "",
"examples": [
"bus"
],
"pattern": "^(.*)$"
},
"path": {
"$id": "#/properties/virtual/items/properties/path",
"type": "string",
"title": "The Path Schema",
"default": "",
"examples": [
"VBUS2"
],
"pattern": "^(.*)$"
},
"entity": {
"$id": "#/properties/virtual/items/properties/entity",
"type": "string",
"title": "The Entity Schema",
"default": "",
"examples": [
"topaz"
],
"enum": ["pde", "topaz"],
"pattern": "^(.*)$"
},
"nodes": {
"$id": "#/properties/virtual/items/properties/nodes",
"type": "array",
"title": "The Nodes Schema",
"items": {
"$id": "#/properties/virtual/items/properties/nodes/items",
"type": "object",
"title": "The Items Schema"
}
}
}
}
}
},
"anyOf": [
{
"if": {
"properties": { "virtual": { "properties": { "entity": { "const": "topaz" } } } }
},
"then": {
"properties": {
"virtual": {
"properties": {
"nodes": {
"items": {
"required": [
"uid",
"utype",
"uaddress",
"unozzles"
],
"properties": {
"uid": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/uid",
"type": "integer",
"title": "The Uid Schema",
"default": 0,
"examples": [
1
]
},
"utype": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/utype",
"type": "string",
"title": "The Utype Schema",
"default": "",
"examples": [
"dispenser"
],
"pattern": "^(.*)$"
},
"uaddress": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/uaddress",
"type": "string",
"title": "The Uaddress Schema",
"default": "",
"examples": [
"false"
],
"pattern": "^(.*)$"
},
"unozzles": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/unozzles",
"type": "boolean",
"title": "The Unozzles Schema",
"default": false,
"examples": [
false
]
}
}
}
}
}
}
}
}
},
{
"if": {
"properties": { "virtual": { "properties": { "entity": { "const" : "pde" } } } }
},
"then": {
"properties": {
"virtual": {
"properties": {
"nodes": {
"items": {
"required": [
"id",
"type",
"address",
"nozzles"
],
"properties": {
"id": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/id",
"type": "string",
"title": "The Id Schema",
"default": "",
"examples": [
"vrt_1"
],
"pattern": "^(.*)$"
},
"type": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/type",
"type": "string",
"title": "The Type Schema",
"default": "",
"examples": [
"dispenser"
],
"pattern": "^(.*)$"
},
"address": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/address",
"type": "integer",
"title": "The Address Schema",
"default": 0,
"examples": [
1
]
},
"nozzles": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/nozzles",
"type": "array",
"title": "The Nozzles Schema",
"items": {
"$id": "#/properties/virtual/items/properties/nodes/items/properties/nozzles/items",
"type": "integer",
"title": "The Items Schema",
"default": 0,
"examples": [
1,
2,
3
]
}
}
}
}
}
}
}
}
}
}
]
}
This JSON is valid:
{
"virtual": [
{
"type": "bus",
"path": "VUS1",
"entity": "pde",
"nodes": [
{
"id": "vrt_1",
"type": "string",
"address": 1,
"nozzles": [1, 2, 3]
},
{
"id": "vrt_2",
"type": "string",
"address": 2,
"nozzles": [1, 2, 3]
}
]
},
{
"type": "bus",
"path": "VUS2",
"entity": "topaz",
"nodes": [
{
"uid": 1,
"utype": "string",
"uaddress": "false",
"unozzles": false
},
{
"uid": "vrt_1",
"utype": "string",
"uaddress": "false",
"unozzles": false
}
]
}
]
}
And this JSON should not be applied, but is considered valid:
{
"virtual": [
{
"type": "bus",
"path": "VUS1",
"entity": "pde",
"nodes": [
{
"id_not_valid": "failure",
"type": 1,
"address": false,
"nozzles": [1, 2, 3]
},
{
"id": "vrt_2",
"type": "string",
"address": false,
"nozzles": [1, 2, 3]
}
]
},
{
"type": "bus",
"path": "VUS2",
"entity": "topaz",
"nodes": [
{
"uid_not_valid": "failure",
"utype": 1,
"uaddress": "false",
"unozzles": false
}
]
}
]
}
In theory, the second JSON should not be validated. For several reasons:
For entity= "pd", the required fields are "id", "type"," address "and"nozzles". In the second line of JSON instead the field "id" is replaced by the field "id_not_valid" - > the obligatory field " id " is absent and validation has to end in failure. The same for entity="top" - "the uid" is replaced by "id_not_valid"
For entity= "pd", the address field is of type token, in the second JSON line it is set to false, which corresponds to the type "boolean", but validation still takes place (the same if you assign an array or string value to address). For entity="top" type, the type is string, but the integer value 1 assigned to it is also assumed by the validator to be the correct string.
But the online validators on the links below say that everything is OK and both JSON conform to the scheme.
The first site
Second site
The third website
So I believe there is an error in the scheme.
The scheme itself was made by this example Example of JSON schema compilation
Any comments and tips on fixing JSON-schema, please
The schema is malformed.
(I'm ignoring the fact that the schema states entity should be "pde" or "topaz", but the instances have "pd" and "top". I assume this is a typo.)
Inside the anyOf, you have two items, each with an if conditional keyword. The schema presented by this keyword is
{
"properties": {
"virtual": {
"properties": {
"entity": {
"const": "topaz"
}
}
}
}
}
This is saying that if virtual has an entity property, then it should be "topaz". But the way that properties works is that it only fails validation if the instance is an object. However in #/properties, you declare that virtual should be an an array of objects where each item contains an entity property.
Since virtual is an array in your instance, none of the if condition keywords in the anyOf pass, so they defer to the else keywords for those subschemas, which don't exist (so the pass by default). This results in both subschemas for the anyOf passing.
I think what you're trying to do is validate each of the items inside the array based on the value of the entity property for that item. This means that you could have both a pde item and a topaz item in the array.
To do this you need to isolate where the variance is. In your case, it's the item level inside the virtual array. This is where you need to put your anyOf.
So you'll want to add your anyOf to #/properties/virtual/items. This is the only point in the schema where an if/then construct can key off of the entity property and enforce the nodes property.
Edit Things I would change
Remove all of the internal $id declarations. They only reiterate the location in the document and provide no additional functionality.
Remove the type and pattern declarations from entity. enum is sufficient here because it declares that the values must be one of the items in the array. Since these are both strings and match the given pattern, those keywords are redundant.
Move the anyOf alongside the properties keyword inside virtual and change it to a oneOf. This is the most specific location where you can access both the entities property and the nodes property. Changing it to a oneOf ensures that exactly one can be true.
Drop the if/then construct and just include the constant value in the then portion.
In the end, it would be structured something like this:
{
... ,
"properties": {
"virtual": {
"type": "array",
"title": "The Virtual Schema",
"items": {
"type": "object",
"title": "The Items Schema",
"required": [ "type", "path", "entity", "nodes" ],
"properties": {
"type": { ... },
"path": { ... },
"entity": {
"title": "The Entity Schema",
"default": "",
"examples": [
"topaz"
],
"enum": ["pde", "topaz"]
}
},
"oneOf": [
{
"properties": {
"entity": {"const": "topaz"},
"nodes": { ... }
}
},
{
"properties": {
"entity": {"const": "pde"},
"nodes": { ... }
}
}
]
}
}
}
}
Here, we're declaring that the items within the virtual array must be objects requiring 4 properties: type, path, entity, and nodes. We explicitly define type, path, entity using the properties keyword. But we conditionally define the nodes property using the oneOf and specifying a constant value for the entity property in each case.

Can't understand this JSON schema from the Swish QR Code API

I'm trying to use an API but the documentation is really bad. I got this JSON schema but I don't understand it. What am I supposed to include in the request?
url: https://mpc.getswish.net/qrg-swish/api/v1/prefilled
I have tried this but it doesn't work:
{
"payee":{
"editable":{
"editable":"false"
},
"swishString":{
"value":"0721876507"
}
},
"size":600,
"border":20,
"transparent":false,
"format":"png"
}
Here's the JSON schema
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Swish pre-filled qr code generator",
"description": "REST interface to get a QR code that the Swish app will interpret as a pre filled code",
"definitions": {
"editable": {
"description ": "Controls if user can modify this value in Swish app or not",
"type": "object",
"properties": {
"editable": {
"type": "boolean",
"default": false
}
}
},
"swishString": {
"type": "object",
"properties": {
"value": {
"type": "string",
"maxLength": 70
}
},
"required": [
"value"
]
},
"swishNumber": {
"type": "object",
"properties": {
"value": {
"type": "number"
}
},
"required": [
"value"
]
}
},
"type": "object",
"properties": {
"format": {
"enum": [
"jpg",
"png",
"svg"
]
},
"payee": {
"description": "Payment receiver",
"allOf": [
{
"$ref": "#/definitions/editable"
},
{
"$ref": "#/definitions/swishString"
}
]
},
"amount": {
"description": "Payment amount",
"allOf": [
{
"$ref": "#/definitions/editable"
},
{
"$ref": "#/definitions/swishNumber"
}
]
},
"message": {
"description": "Message for payment",
"allOf": [
{
"$ref": "#/definitions/editable"
},
{
"$ref": "#/definitions/swishString"
}
]
},
"size": {
"description": "Size of the QR code. The code is a square, so width and height are the same. Not required is the format is svg",
"value": "number",
"minimum": 300
},
"border": {
"description": "Width of the border.",
"type": "number"
},
"transparent": {
"description": "Select background color to be transparent. Do not work with jpg format.",
"type": "boolean"
}
},
"required": [
"format"
],
"anyOf": [
{
"required": [
"payee"
]
},
{
"required": [
"amount"
]
},
{
"required": [
"message"
]
}
],
"additionalProperties": false,
"maxProperties": 5
}
The API should return a QR code.
To be honest, I have not taken the time to learn JSON schema, but your example should probably look something like this:
{
"payee": {
"value": "0721876507",
"editable": false
},
"size": 600,
"border": 20,
"transparent": false,
"format": "png"
}
There are other parameters you may choose to utilize:
{
"payee": {
"value": "1239006032",
"editable": false
},
"message": {
"value": "LIV",
"editable": true
},
"amount": {
"value": 100,
"editable": true
},
"format": "png",
"size": 300,
"border": 0,
"transparent": true
}
Honestly, I think the developers behind the Swish APIs are trying to look smart by complicating things. They should, of course, have provided example JSON data instead of forcing consumers to understand their JSON schema. Also, I believe their published schema is wrong. The second example I provided works even though it doesn't validate according to the JSON schema ("Object property count 7 exceeds maximum count of 5").
Here is a minimal and pretty useless request that returns a valid QR-code
{
"format": "png",
"size": 300
}
And here is a more usable example that works
{
"format": "png",
"size": 300,
"transparent": false,
"amount": {
"value": 999.99,
"editable": true
},
"payee": {
"value": "0701000000",
"editable": false
},
"message": {
"value": "Hello",
"editable": false
}
}

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

Is "type" optional in Json schema

{
"$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"]
}
}
In the above Json schema "dimensions"is of "type": "object" , is type optional , if "type" is not specified should i assume it to be object. Could not find anything in specs related to optional elements.
https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-03#section-5.1
If the property is not defined or is not in this list, then any
type of value is acceptable.
type is optional, ANY value is acceptable if type is omitted.
I think it is not optional. As you can see in the meta-schema below, the property "type" has no default value:
http://json-schema.org/schema
Also in my JSON Schema library NJsonSchema I set the type to None instead of Object. Check out the TypeRaw property:
https://github.com/rsuter/NJsonSchema/blob/master/NJsonSchema/JsonSchema4.Serialization.cs
When the default value is set to Object a lot more tests from the JSON Schema test suite fail. Maybe you can find a definite answer in this JSON Schema test suite:
https://github.com/json-schema/JSON-Schema-Test-Suite

Recursive JSON Schema

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