Easy way to group custom defined types to use for reference? - jsonschema

How to reference types by group instead of doing it individually?
For example here, I want "sum" and "subtract" types to accept types that are "number"-related types only("number", "sum", "subtract"). While "concatenate" can accept both "number" and "string"-related types. Including their selves. This will be really helpful for me if in case I added more types and want them to be automatically included.
"sum": {
"title": "sum",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
},
"required": [
"values"
]
},
"subtract": {
"title": "subtract",
"type": "object",
"properties": {
"minuend": {
"type": "number"
},
"subtrahend": {
"type": "number"
}
},
"required": [
"minuend",
"subtrahend"
]
},
"concatenate": {
"title": "concatenate",
"type": "object",
"properties": {
"strings": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
},
"required": [
"strings"
]
}
}
Here's the full schema:
{
"definitions": {
"sum": {
"title": "sum",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
},
"required": [
"values"
]
},
"subtract": {
"title": "subtract",
"type": "object",
"properties": {
"minuend": {
"type": "number"
},
"subtrahend": {
"type": "number"
}
},
"required": [
"minuend",
"subtrahend"
]
},
"concatenate": {
"title": "concatenate",
"type": "object",
"properties": {
"strings": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
},
"required": [
"strings"
]
}
},
"title": "Step",
"type": "object",
"properties": {
"value": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
}

Related

json schema validation: a string field required if another array field contains specific value

cant build validation for simple case:
if sources field contains "OTHER" in values then "sourceOtherDescription" must be required.
Shall pass validation
{
"sources": ["RENTS"]
}
{
"sources": ["RENTS", "OTHER"],
"sourceOtherDescription": "other income"
}
This should not pass validation since sources contains "OTHER"
{
"sources": ["RENTS", "OTHER"]
}
The schema that I was able to produce. Does not really work
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "money-sources",
"title": "Money Sources",
"description": "Money Sources definitions",
"type": "object",
"required": ["sources"],
"properties": {
"sources": {
"type": "array",
"items": {
"type": "string",
"enum": [
"RENTS",
"MEMBER_FEES",
"PROFIT",
"SALES_SECURITIES",
"INTERNAL_GROUP_TRANSFERS",
"OTHER"
]
},
"uniqueItems": true
},
"sourceOtherDescription": { "type": "string", "minLength": 3}
},
"additionalProperties": false,
"oneOf": [
{
"properties": {
"sources": {
"type": "array",
"contains": {"const": "OTHER"}
}
},
"required": ["sourceOtherDescription"]
},
{
"properties": {
"sources": {
"type": "array",
"contains": {
"enum": [
"RENTS",
"MEMBER_FEES",
"PROFIT",
"SALES_SECURITIES"
]
}
}
}
}
, false
]
}
Using if-then it works for me this way:
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "money-sources",
"title": "Money Sources",
"description": "Money Sources definitions",
"type": "object",
"required": [ "sources" ],
"properties": {
"sources": {
"type": "array",
"items": {
"type": "string",
"enum": [
"RENTS",
"MEMBER_FEES",
"PROFIT",
"SALES_SECURITIES",
"INTERNAL_GROUP_TRANSFERS",
"OTHER"
]
},
"uniqueItems": true
},
"sourceOtherDescription": {
"type": "string",
"minLength": 3
}
},
"additionalProperties": false,
"if": {
"properties": {
"sources": {
"type": "array",
"contains": {
"const": "OTHER"
}
}
}
},
"then": {
"required": [ "sourceOtherDescription" ]
}
}

JSONSchema validation failure with $ref (Draft v3)

I have created a JSON schema following the draft v3 specifications. Schema looks like this:
{
"$schema": "http://json-schema.org/draft-03/schema#",
"additionalProperties": false,
"type": "object",
"properties": {
"ExecutionPlanList": {
"type": "array",
"items": [{
"type": "object",
"properties": {
"model": {
"required": true,
"properties": {
"featureList": {
"required": true,
"items": {
"properties": {
"featureName": {
"type": ["string", "null"]
},
"featureType": {
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"modelId": {
"required": true,
"type": "string"
}
},
"type": "object"
},
"cascadeSteps": {
"required": false,
"items": {
"properties": {
"binaryModel": {
"$ref": "#/properties/ExecutionPlanList/items/properties/model",
"required": true
},
"threshold": {
"required": true,
"default": "0.0",
"maximum": 100.0,
"type": "number"
},
"backupModel": {
"$ref": "#/properties/ExecutionPlanList/items/properties/model",
"required": true
}
}
},
"type": "array"
},
"marketplaceId": {
"required": true,
"type": "integer"
}
}
}]
}
},
"required": true
}
Essentially, executionPlanList contains list of model and cascadeStep, and each cascadeStep contains two models with a number. So I'm trying to re-use the schema for model in cascadeStep, but validation (https://www.jsonschemavalidator.net/) is failing with Could not resolve schema reference '#/properties/ExecutionPlanList/items/properties/model'.
Would appreciate any pointers on what's wrong with this schema.
what about adding a 'definitions' and refer like this:
{
"$schema": "http://json-schema.org/draft-03/schema#",
"additionalProperties": false,
"type": "object",
"definitions": {
"model": {
"required": true,
"properties": {
"featureList": {
"required": true,
"items": {
"properties": {
"featureName": {
"type": ["string", "null"]
},
"featureType": {
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"modelId": {
"required": true,
"type": "string"
}
},
"type": "object"
}
},
"properties": {
"ExecutionPlanList": {
"type": "array",
"items": [{
"type": "object",
"properties": {
"model": {
"$ref" : "#/definitions/model"
},
"cascadeSteps": {
"required": false,
"items": {
"properties": {
"binaryModel": {
"$ref" : "#/definitions/model",
"required": true
},
"threshold": {
"required": true,
"default": "0.0",
"maximum": 100.0,
"type": "number"
},
"backupModel": {
"$ref" : "#/definitions/model",
"required": true
}
}
},
"type": "array"
},
"marketplaceId": {
"required": true,
"type": "integer"
}
}
}]
}
},
"required": true
}
It should be '#/properties/ExecutionPlanList/items/0/properties/model'
The schema validates only the first item, by the way.

Using a json schema in multiple layouts

I'm helping to build an interface that works with Json Schema, and I have a question about interface generation based on that schema. There are two display types - one for internal users and one for external users. Both are dealing with the same data, but the external users should see a smaller subset of fields than the internal users.
For example, here is one schema, it defines an obituary:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "",
"type": "object",
"required": [
"id",
"deceased"
],
"properties": {
"id": { "type": "string" },
"account": {
"type": "object",
"required": [
"name"
],
"properties": {
"id": { "type": "number" },
"name": { "type": "string" },
"website": {
"anyOf": [
{
"type": "string",
"format": "uri"
},
{
"type": "string",
"maxLength": 0
}
]
},
"email": {
"anyOf": [
{
"type": "string",
"format": "email"
},
{
"type": "string",
"maxLength": 0
}
]
},
"address": {
"type": "object",
"properties": {
"address1": { "type": "string" },
"address2": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"postalCode": { "type": "string" },
"country": { "type": "string" }
}
},
"phoneNumber": {
"anyOf": [
{
"type": "string",
"format": "phone"
},
{
"type": "string",
"maxLength": 0
}
]
},
"faxNumber": {
"anyOf": [
{
"type": "string",
"format": "phone"
},
{
"type": "string",
"maxLength": 0
}
]
},
"type": { "type": "string" }
}
},
"deceased": {
"type": "object",
"required": [
"fullName"
],
"properties": {
"fullName": { "type": "string" },
"prefix": { "type": "string" },
"firstName": { "type": "string" },
"middleName": { "type": "string" },
"nickName": { "type": "string" },
"lastName1": { "type": "string" },
"lastName2": { "type": "string" },
"maidenName": { "type": "string" },
"suffix": { "type": "string" }
}
},
"description": { "type": "string" },
"photos": {
"type": "array",
"items": { "type": "string" }
}
}
}
Internal users would be able to access all the fields, but external users shouldn't be able to read/write the account fields.
Should I make a second schema for the external users, or is there a way to indicate different display levels or public/private on each field?
You cannot restrict acess to the fields defined in a schema, but you can have 2 schema files, one defining the "public" fields, and the other one defining the restricted fields plus including the restricted fields.
So
public-schema.json:
{
"properties" : {
"id" : ...
}
}
restricted-schema.json:
{
"allOf" : [
{
"$ref" : "./public-schema.json"
},
{
"properties" : {
"account": ...
}
}
]
}

JSON schema for object with either A and B or C required properties

I have two possible JSON objects for one request:
{
"from": "string",
"to": "string",
"text": "string"
}
or
{
"number": "integer",
"text": "string"
}
In both cases "text" property is optional. Other properties are required (either "number, or both "from" and "to").
What will be the correct JSON schema to validate this?
Here is another solution that I think is a bit more clear. The dependencies clause ensures that "from" and "to" always come as a pair. Then the oneOf clause can be really simple and avoid the not-required boilerplate.
{
"type": "object",
"properties": {
"from": { "type": "string" },
"to": { "type": "string" },
"number": { "type": "integer" },
"text": { "type": "string" }
},
"dependencies": {
"from": ["to"],
"to": ["from"]
},
"oneOf": [
{ "required": ["from"] },
{ "required": ["number"] }
]
}
Finally managed to build the correct scheme.
{
"definitions": {
"interval": {
"type": "object",
"properties": {
"from": {
"type": "string"
},
"to": {
"type": "string"
},
"text": {
"type": "string"
}
},
"required": ["from", "to"],
"not": {
"required": ["number"]
}
},
"top": {
"type": "object",
"properties": {
"number": {
"type": "integer"
},
"text": {
"type": "string"
}
},
"required": ["number"],
"allOf": [
{
"not": {
"required": ["from"]
}
},
{
"not": {
"required": ["to"]
}
}
]
}
},
"type": "object",
"oneOf": [
{"$ref": "#/definitions/interval"},
{"$ref": "#/definitions/top"}
]
}

JSONSchema v4 - Error when resolving schema reference - Definitions and References

When trying to validate the following schema using http://www.jsonschemavalidator.net/,
{
"id": "http://some.site.somewhere/entry-schema#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "schema for the FormularSpecification",
"definitions": {
"elementId": {
"id": "http://jsonschema.net/elementId",
"type": "string"
},
"mappingKey": {
"id": "http://jsonschema.net/mappingKey",
"type": "string"
},
"elementType": {
"id": "http://jsonschema.net/elementType",
"type": "string"
},
"length": {
"id": "http://jsonschema.net/length",
"type": "integer"
},
"label": {
"id": "http://jsonschema.net/label",
"type": "string"
},
"content": {
"id": "http://jsonschema.net/content",
"type": "string"
},
"placeholder": {
"id": "http://jsonschema.net/placeholder",
"type": "string"
},
"date": {
"id": "http://jsonschema.net/date",
"type": "string"
},
"option": {
"id": "http://jsonschema.net/option",
"type": "object",
"properties": {
"elementId": { "$ref": "#/definitions/elementId" },
"label": { "$ref": "#/definitions/label" }
},
"required": ["elementId", "label"]
},
"options": {
"id": "http://jsonschema.net/options",
"type": "array",
"items": { "$ref": "#/definitions/option" },
"minItems": 1,
"uniqueItems": true
},
"textfield": {
"id": "http://jsonschema.net/textfield",
"type": "object",
"properties": {
"elementId": { "$ref": "#/definitions/elementId" },
"length": { "$ref": "#/definitions/length" },
"label": { "$ref": "#/definitions/label" },
"placeholder": { "$ref": "#/definitions/placeholder" },
"textfieldType": {
"enum": [ "text", "ext4", "btrfs" ]
}
},
"required": ["elementId", "length", "label", "placeholder", "textfieldType"]
},
"checkbox": {
"id": "http://jsonschema.net/checkbox",
"type": "object",
"properties": {
"label": { "$ref": "#/definitions/label" }
},
"required": ["label"]
},
"radio": {
"id": "http://jsonschema.net/radio",
"type": "object",
"properties": {
"label": { "$ref": "#/definitions/label" },
"options": { "$ref": "#/definitions/options" }
},
"required": ["label", "options"]
},
"dropdown": {
"id": "http://jsonschema.net/dropdown",
"type": "object",
"properties": {
"label": { "$ref": "#/definitions/label" },
"options": { "$ref": "#/definitions/options" }
},
"required": ["label", "options"]
},
"validator": {
"id": "http://jsonschema.net/validator",
"type": "object",
"properties": {
"elementId": { "$ref": "#/definitions/elementId" }
}
},
"validators": {
"id": "http://jsonschema.net/validators",
"type": "array",
"items": { "$ref": "#/definitions/validator" }
},
"interactiveDetails": {
"type": "object",
"oneOf": [
{ "textfield": { "$ref": "#/definitions/textfield" } },
{ "checkbox": { "$ref": "#/definitions/checkbox" } },
{ "radio": { "$ref": "#/definitions/radio" } },
{ "dropdown": { "$ref": "#/definitions/dropdown" } },
{ "date": { "$ref": "#/definitions/date" } }
]
},
"interactive": {
"id": "http://jsonschema.net/interactive",
"type": "object",
"properties": {
"elementId": { "$ref": "#/definitions/elementId" },
"elementType": { "$ref": "#/definitions/elementType" },
"mappingKey": { "$ref": "#/definitions/mappingKey" },
"validators": { "$ref": "#/definitions/validators" },
"interactiveDetails" : { "$ref": "#/definitions/interactiveDetails" }
},
"required": ["elementId", "elementType", "mappingKey", "validators"]
},
"interactives": {
"id": "http://jsonschema.net/interactives",
"type": "array",
"items": { "$ref": "#/definitions/interactive" }
},
"description": {
"id": "http://jsonschema.net/description",
"type": "object",
"properties": {
"elementId": { "$ref": "#/definitions/elementId" },
"elementType": { "$ref": "#/definitions/elementType" },
"content": { "$ref": "#/definitions/content" }
},
"required": ["elementId", "elementType", "content"]
},
"descriptions": {
"items": { "$ref": "#/definitions/description" }
},
"children": {
"items": {
"anyOf": [
{ "$ref": "#/definitions/group" },
{ "$ref": "#/definitions/question" }
]
},
"minItems": 1
},
"question": {
"type": "object",
"properties": {
"elementId": { "$ref": "#/definitions/elementId" },
"descriptions": { "$ref": "#/definitions/descriptions" },
"interactives": { "$ref": "#/definitions/interactives" }
},
"required": ["elementId", "descriptions", "interactives"]
},
"group": {
"type": "object",
"properties": {
"elementId": { "$ref": "#/definitions/elementId" },
"descriptions": { "$ref": "#/definitions/descriptions" },
"children": { "$ref": "#/definitions/children"}
},
"required": ["elementId", "descriptions", "children"]
}
},
"type": "object",
"properties": {
"elementId": { "$ref": "#/definitions/elementId" },
"description": { "$ref": "#/definitions/descriptions" },
"children": { "$ref": "#/definitions/children" }
},
"required": [
"elementId",
"descriptions",
"children"
]
}
I'm getting the following error:
Error when resolving schema reference '#/definitions/elementId'. Path 'definitions.description.properties.elementId', line 135, position 30.
I cannot figure out what the problem is. I scanned the documentation several times and had a look at tutorials, but I do not have any clue.
The semantics of the id keyword are are a bit confusing. I'm not sure I completely understand it myself. In general it is almost never a good idea to include id anywhere other than the root of your schema.
The "id" keyword (or "id", for short) is used to alter the resolution scope. When an id is encountered, an implementation MUST resolve this id against the most immediate parent scope. The resolved URI will be the new resolution scope for this subschema and all its children, until another id is encountered.
http://json-schema.org/latest/json-schema-core.html#anchor27
Consider the following excerpt from you schema. Because you include the id keyword, your "elementId" and "label" $refs don't resolve against the root of the document as you expect, they resolve from the nearest parent schema id.
"option": {
"id": "http://jsonschema.net/option",
"type": "object",
"properties": {
"elementId": { "$ref": "#/definitions/elementId" },
"label": { "$ref": "#/definitions/label" }
},
"required": ["elementId", "label"],
"definitions": { ... } <-- your $refs expect values here
}
},
I have seen that in some circles, people write schemas with ids for every subschema. I'm not sure what benefit they think they are getting out of doing that, but I suspect that they think of id as just a label and don't understand how it alters resolution scope.
If you do have good reason to use ids everywhere and want to leave them in, you can always explicitly reference the root id when you have a conflict.
{ "$ref": "http://some.site.somewhere/entry-schema#definitions/elementId" }