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

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

Related

Generic json schema for two condition based responses

I have an API returning response based on input type.
For a single filter I get
{
"intervalData": [
{
"timestamp": "2021-05-25T06:00:00.000Z",
"result": {
"Attempts": 309194
}
}
],
"intervalTotals": {
"Attempts": 4719471
}
}
For multiple filter I get
{
"multiFilterData": [
{
"filter": {
"id": 111111
},
"intervalData": {
"timestamp": "2021-05-25T20:41:39.000Z",
"result": {
"Attempts": 7902
}
}
},
{...}
]
}
That means the response will either have (intervalData,intervalTotals) OR multiFilterData.
Question:
Is it possible to have a generic schema to handle this or must I have two separate schemas?
How to make sure that if one combination is present other should not be there?
I tried with below schema on https://www.jsonschemavalidator.net/. The validation fails if there is some other keys listed under the required, unfortunately the validation succeeds if one of the entry from oneOf is missing. EDIT1 below
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"oneOf": [
{
"required": [
"intervalData",
"intervalTotals",
]
},
{
"required": [
"multiFilterData",
]
}
],
"properties": {
"intervalData": {
"type": "array",
"additionalItems": false,
"items": {
"type": "object",
"required": [
"timestamp",
"result"
],
"properties": {
...
},
"additionalProperties": false
}
},
"intervalTotals": {
"type": "object",
"required": [
"Attempts"
],
"properties": {
"Attempts": {
"type": "integer"
}
},
"additionalProperties": false
},
"multiFilterData": {
"type": "array",
"additionalItems": false,
"items": {
"type": "object",
"required": [
"filter",
"intervalData"
],
"properties": {
"filter": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "integer"
}
},
"additionalProperties": false
},
"intervalData": {
"type": "object",
"required": [
"timestamp",
"result"
],
"properties": {
"timestamp": {
"type": "string"
},
"result": {
"type": "object",
"required": [
"Attempts"
],
"properties": {
...
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
}
EDIT 1: This schema also passes even though the first required is missing an element on the list.
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"oneOf": [
{
"required": [
"intervalData"
]
},
{
"required": [
"multiFilterData",
]
}
],
"properties": {
"intervalData": {...},
"intervalTotals": {...},
"multiFilterData": {...}
},
"additionalProperties": false
}

jsonschema for array type validates incorrect data, how to fix?

I have following jsonschema:
{
"$schema": "http://json-schema.org/schema#",
"type": "object",
"properties": {
"abc": {
"type": "array",
"item": {
"type": "object",
"minItems": 1,
"properties": {
"a" : {"type": "string"},
"b" : {"type": "string"}
},
"required": [ "a", "b" ]
}
}
},
"required": [ "abc" ]
}
If I pass to validator following data:
{
"abc": [
{
},
{
}
]
}
validator will output no error, but such data incorrect.
You used item rather than items.
Additionally, "minItems": 1 needs to be moved up to the parent object.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"abc": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string"
}
},
"required": [
"a",
"b"
]
}
}
},
"required": [
"abc"
]
}
Checked and validated using https://jsonschema.dev

Content of an property dependent on another property value

I have the following schema, which "works", but does not enforce all the rules required of it.
I get JSON with a series of questions that have a templateType and data properties. There are different templates for each type, and the type must fit the template (or the client doesn't know how to layout the data).
The schema validates the templateType as an enum, and that the data fits one of the templates, but there's no correlation between the type and data structure (e.g. I could get templateType yesNo and data structure for multiSelect).
I'd like it to validate that the templateType matches the data structure. I can't change the format of the generated JSON, only the schema that validates it. None of the questions I've looked at seem to provide a solution.
For help, the schema can be pasted into the editor at http://jeremydorn.com/json-editor/, which generates a form from the schema and JSON data based on selections and data entered into the form.
{
"definitions": {
"question": {
"type": "array",
"title": "Question",
"items": {
"$ref": "#/definitions/template"
}
},
"template": {
"type": "object",
"title": "Question template",
"required": ["templateType","data"],
"properties": {
"templateType": {
"type": "string",
"enum": ["yesNo","multiSelect"]
},
"data": {
"oneOf": [
{"$ref": "#/definitions/yesNo"},
{"$ref": "#/definitions/multiSelect"}
]
}
}
},
"yesNo": {
"type": "object",
"title": "Yes/No question",
"additionalProperties": false,
"properties": {
"label": {
"type": "string"
}
}
},
"multiSelect": {
"type": "array",
"title": "Multi-select question",
"items": {
"type": "string",
"title": "Label for option",
"additionalProperties": false
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"$ref": "#/definitions/question"
}
}
Have you considered using if, then, else keywords in your schema? They're part of JSON Schema draft-07
It would look like this:
{
"definitions": {
"question": {
"type": "array",
"title": "Question",
"items": {
"$ref": "#/definitions/template"
}
},
"template": {
"type": "object",
"title": "Question template",
"required": ["templateType","data"],
"properties": {
"templateType": {
"type": "string",
"enum": ["yesNo","multiSelect"]
},
"data": {
"if": { "properties": { "templateType": { "pattern": "^yesNo$" } } },
"then": { "$ref": "#/definitions/yesNo" },
"else": { "$ref": "#/definitions/multiSelect" }
}
}
},
"yesNo": {
"type": "object",
"title": "Yes/No question",
"additionalProperties": false,
"properties": {
"label": {
"type": "string"
}
}
},
"multiSelect": {
"type": "array",
"title": "Multi-select question",
"items": {
"type": "string",
"title": "Label for option",
"additionalProperties": false
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"$ref": "#/definitions/question"
}
}
If if/then/else isn't supported by your validator, an alternative could be:
{
"definitions": {
"question": {
"type": "array",
"title": "Question",
"items": {
"$ref": "#/definitions/template"
}
},
"template": {
"type": "object",
"title": "Question template",
"required": ["templateType","data"],
"anyOf": [
{
"properties": {
"templateType": { "type": "string", "pattern": "yesNo" },
"data": { "$ref": "#/definitions/yesNo" }
}
},
{
"properties": {
"templateType": { "type": "string", "pattern": "multiSelect" },
"data": { "$ref": "#/definitions/multiSelect" }
}
}
]
},
"yesNo": {
"type": "object",
"title": "Yes/No question",
"additionalProperties": false,
"properties": {
"label": {
"type": "string"
}
}
},
"multiSelect": {
"type": "array",
"title": "Multi-select question",
"items": {
"type": "string",
"title": "Label for option",
"additionalProperties": false
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {
"$ref": "#/definitions/question"
}
}

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.

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