JSON Schema Custom Definition - json

Can I have a custom specifier/attribute like "required" keyword to decorate my Json schema fields with custom specifications.
Like for example:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"id": {
"description": "The unique identifier for a product",
"type": "integer"
},
"name": {
"description": "Name of the product",
"type": "string"
},
"price": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
"**credit-card**": {
"**type**": "**number**",
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
"required": ["id", "name", "price"],
"**confidential**" : ["**credit-card**"]
}
Can I have a special keyword called "confidential" to make sure that "credit-card" should not be revealed and/or masked? Does the schema standards allow for such custom metadata keywords?

It depends on the library you will use to execute the validation. I've used AJV, it allows you to define custom keywords, you can find more information about it here.

Related

JsonSchema definition path and subschema re-use

Lets say I have two schemas defined as follows -
ADDRESS_CLASS_SCHEMA_DEFINITION = {
"title": "Address",
"type": "object",
"properties": {
"country_code": {
"$ref": "#/definitions/CountryCode"
},
"city_code": {
"title": "City Code",
"type": "string"
},
"zipcode": {
"title": "Zipcode",
"type": "string"
},
"address_str": {
"title": "Address Str",
"type": "string"
}
},
"required": [
"country_code",
"city_code",
"zipcode"
],
"definitions": {
"CountryCode": {
"title": "CountryCode",
"description": "An enumeration.",
"enum": [
"CA",
"USA",
"UK"
],
"type": "string"
}
}
}
EMPLOYEE_CLASS_SCHEMA_DEFINITION = {
"title": "Employee",
"type": "object",
"properties": {
"id": {
"title": "Id",
"type": "integer"
},
"name": {
"title": "Name",
"type": "string"
},
"email": {
"title": "Email",
"type": "string"
},
"telephone": {
"title": "Telephone",
"type": "string"
},
"address": {
"$ref": "#/definitions/Address"
}
},
"required": [
"id",
"name",
"email"
],
"definitions": {
"Address": ADDRESS_CLASS_SCHEMA_DEFINITION
}
}
I'm trying to re-use sub-schema definitions by defining a constant and referencing them individually in definitions (for example address-schema is referenced through constant in employee-schema definition). This approach works for individual schemas, however there seems to be a json-pointer path issue for Employee schema - #/definitions/CountryCode wouldn't resolve in Employee schema. I was assuming that #/definitions/CountryCode would be a relative path on Address schema as its scope is defined on a sub-schema, but my understanding seems wrong. I can make it work by flattening out like below, however I donot want to take this route -
{
"title": "Employee",
"type": "object",
"properties": {
"id": {
"title": "Id",
"type": "integer"
},
"name": {
"title": "Name",
"type": "string"
},
"email": {
"title": "Email",
"type": "string"
},
"telephone": {
"title": "Telephone",
"type": "string"
},
"address": {
"$ref": "#/definitions/Address"
}
},
"required": [
"id",
"name",
"email"
],
"definitions": {
"CountryCode": {
"title": "CountryCode",
"description": "An enumeration.",
"enum": [
"CA",
"USA",
"UK"
],
"type": "string"
},
"Address": {
"title": "Address",
"type": "object",
"properties": {
"country_code": {
"$ref": "#/definitions/CountryCode"
},
"city_code": {
"title": "City Code",
"type": "string"
},
"zipcode": {
"title": "Zipcode",
"type": "string"
},
"address_str": {
"title": "Address Str",
"type": "string"
}
},
"required": [
"country_code",
"city_code",
"zipcode"
]
}
}
}
I'm wondering how to fix this, I've briefly looked into jsonschema-bundling and using $id but from best practices it seems like the general recommendation is to use $id when dealing with URI's alone. Would like to know about best practices and how to fix this problem, would also appreciate if someone can point me on how to use $id correctly (for example, constant based approach seems to work when I provide identifiers like $id: Address, $id: Employee). Thanks in advance.
JSON Schema implementations work in JSON land. When you combine your schemas in your example above, presumably in javascript/node.js, by the time it gets to the JSON Schema implementation for validation execution, any knowledge that there were separate schemas is lost. (It's generally not considered that this approach is the best approach.)
The EASY fix here SHOULD be just to define $id in each of the roots of your schemas. These should be a fully qualfied URI. It doesn't really matter what they are at this point. They could be https://example.com/a and https://example.com/b. Then, in the primary schema, you can do $ref: https://example.com/b.
Implementations should provide you with a way to load in your other/non-primary schemas so the $id values can be stored in an index. Using $id in your other schema with a fully qualified URI will signify a "resource boundary".
https://json-schema.hyperjump.io is the only web playground to support multiple files/schemas/"Schema Resources", so you can test this out there to confirm your expectations.
Not all implementations make it easy or even provide a means to import your other schemas, but they should.
If you have follow up questions, feel free to leave a comment, or join the JSON Schema slack server if it would be off-topic for StackOverflow.

How to check for matching properties using a JSON schema?

I'm making a Discord bot in Python that reacts to certain keywords in messages and my script uses a JSON file that might for example look like this:
{
"characters": {
"john": {
"name": "Johnny",
"hex_colour": "0xC61B1B"
},
"marc": {
"name": "Marcus",
"hex_colour": "0x8AC0FF"
}
},
"reactions": [
{
"keywords": ["Hi", "Hello"],
"quotes": {
"john": ["Hello my name is Johnny"]
"marc": [
"Hi there. I'm Marcus.",
"Not now, I'm looking for John, have you seen him?"
]
}
},
{
"keywords": ["Bye"],
"quotes": {
"john": ["See you later!"]
}
}
]
}
As you can see the structure is quite complex, so I decide to make a schema for it so vscode could point out any issues. It currently looks like this:
{
"title": "Quotes data",
"description": "Quotes bot data file",
"type": "object",
"properties": {
"characters": {
"title": "Character collection",
"description": "A collection of the available characters.",
"type": "object",
"additionalProperties":{
"title": "Character tag",
"description": "A tag that represents the character as a short string",
"type": "object",
"properties": {
"name": {
"title": "Character name",
"description": "The name of the character.",
"type": "string"
},
"hex_colour": {
"title": "Character colour",
"description": "The hex code of the colour in 0x000000 format.",
"type": "string"
},
"image_url": {
"title": "Character image",
"description": "An url to an image of the character.",
"type": "string"
}
},
"required": ["name"],
"additionalProperties": false
}
},
"reactions": {
"title": "Reaction collection",
"description": "A list of the reactions",
"type": "array",
"items": {
"type": "object",
"properties": {
"keywords": {
"title": "Keyword list",
"description": "A list of keywords for the bot to react to.",
"type": "array",
"items": {
"title": "Keyword",
"type": "string",
"minItems": 1,
"uniqueItems": true
}
},
"quotes": {
"title": "Quotes collection",
"description": "A collection of characters with quotes.",
"type": "object",
"additionalProperties":{
"title":"Character tag",
"description": "A tag that matches a character above.",
"type": "array",
"items": {
"title": "Quote",
"description": "A quote to react with.",
"type": "string",
"minItems": 1,
"uniqueItems": true
}
}
}
},
"required": ["keywords", "quotes"],
"additionalProperties": false
}
}
},
"required": ["characters", "reactions"],
"additionalProperties": true,
"allowTrailingCommas": true
}
So for the properties of the "characters" object, any property name is allowed, therefore I use "additionalProperties". Later on, for the "quotes" object, I did the same. But in this case, not any property should be allowed. Only those that match one of the properties of the "characters" object is allowed. Is there any way to make the schema check for matching properties?
This is a very specific semantic check and not possible using the standard specification of JSON Schema. Validation can't access an arbitrary set of property names and also can't look up the validation path. You would need to add this as application code.

Validation of presence of certain keys in an EAV payload depending on value of another field in the payload using json schema validator

I have following schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Bulk Create Entity",
"title": "Bulk Create Entity",
"type": "object",
"properties": {
"idempotence_key": {
"description": "Idempotence Key",
"type": "string"
},
"requested_by": {
"description": "Requested By",
"type": "string"
},
"updated_by_process_id": {
"description": "Process id which is creating this entity.",
"type": "string"
},
"entity_creation_requests": {
"description": "Entity creation requests.",
"type": "array",
"minItems": 1,
"items": {
"title": "Entity Creation Request",
"type": "object",
"properties": {
"type": {
"description": "Entity Type",
"type": "string"
},
"taxonomies": {
"description": "Entity Taxonomies",
"type": "array",
"items": {
"title": "Taxonomy",
"type": "object",
"properties": {
"name": {
"description": "Taxonomy Name",
"type": "string"
},
"value": {
"description": "Taxonomy Value",
"type": "string"
}
}
}
}
}
}
}
},
"required": [
"idempotence_key",
"requested_by",
"updated_by_process_id",
"entity_creation_requests"
]
}
Here, the root level payload is an object which has a key "entity_creation_requests" which is an array of objects which in turn have an array property "taxonomies" which contains a list of key-value pairs.
Now depending on the "type" of the request under "entity_creation_requests", I want to validate the presence of certain keys in the taxonomies list.
For example, for the creation request of type "product", I want keys "MRP", "seller" etc. to be present in the taxonomies list.
Can we achieve this using JSON schema validator?
{Here is something I have created: https://codebeautify.org/jsonviewer/cb80c728}
Are there any other alternatives?
I am using this in an spring boot application (Java).

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

How do I inherit from schemas that are in the same file?

Given the following schema fragment
{
"$schema": "http://json-schema.org/schema#",
"definitions": {
"uuid": {
"title": "uuid",
"description": "UUID ( http://regex101.com/r/eJ7gN2 )",
"type": "string",
"minLength": 36,
"maxLength": 36,
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
},
"reference": {
"title": "reference",
"description": "A reference to an object by UUID",
"type": "object",
"properties" : {
"id": {
"$ref": "#/definitions/uuid"
}
},
"required": [ "id" ]
},
"imageref": {
"title": "imageref",
"description": "Reference to an image using an internal UUID",
"type": "object",
"properties": {
"size": {
"description": "Largest side of the image, depends on aspect ratio",
"type": "integer",
"minimum": 0,
"maximum": 1600
},
"crop": {
"description": "Flag to tell the system to crop the image or not",
"type": "boolean",
"default": false
}
}
}
}
}
How do I specify that imageref should inherit from reference, so that imageref has the id property that is in reference?
I have lots of other things that will be reference types and I am trying to eliminate duplicating that definition over and over again.
To inherit from another schema, you use allOf combined with $ref:
{
"title": "Extension schema",
"allOf": [{"$ref": "/path/to/base/schema"}]
}
Inheriting from another schema within the same file is just the same - you reference it using fragments, just like you have elsewhere:
{
"title": "Extension schema",
"allOf": [{"$ref": "#/definitions/reference"}]
}