jsonSchema nested attribute conditionally required - jsonschema

In jsonschema, how can we make some of the inner attributes required based on the field values present outside.
In the following example,
{
"type" : "a/b/c",
"args": {
"propA1": "",
"propA2": "",
"propB1": "",
"propC1": "",
"propC2": "",
"c1": "",
"c2": "",
"c3": ""
}
}
type can be a or b or c. args is always required.
conditions are,
propA1, propA2 are required if type is a,
propB1 is required if type is b and,
propC1, propC2 are required if type is c.
c1, c2 and c3 are always required
What I have done so far is,
"properties": {
"type": {"enum": ["a", "b", "c"]},
"args": {
"type": "object",
"properties": {
"propA1": {"type":"string" },
"propA2": {"type":"string" },
"propB1": {"type":"string" },
"propC1": {"type":"string" },
"propC2": {"type":"string" },
"c1": {"type":"string" },
"c2": {"type":"string" },
"c3": {"type":"string" }
}
"required": ["c1", "c2", "c3"]
}
"anyOf": [{
"type": {"enum": ["a"]}
// how to specify required for inner properties of args?
}, {
"type": {"enum": ["b"]}
}, {
"type": {"enum": ["c"]}
}]
},
"required": ["type", "args"]
Here how can we specify required for inner properties without repeating common properties in each object of anyOf?

You need to use "properties" inside of the "anyOf" the same way you use it in the main schema. So just put both "type" (with the appropriate single-value "enum" and then "args" with the appropriate "required" inside of it. You do not need to repeat the other contents of "args". It should look like this (although I haven't tested it).
"properties": {
"type": {"enum": ["a", "b", "c"]},
"args": {
"type": "object",
"properties": {
"propA1": {"type":"string" },
"propA2": {"type":"string" },
"propB1": {"type":"string" },
"propC1": {"type":"string" },
"propC2": {"type":"string" },
"c1": {"type":"string" },
"c2": {"type":"string" },
"c3": {"type":"string" }
}
"required": ["c1", "c2", "c3"]
}
"anyOf": [{
"properties": {
"type": {"enum": ["a"]},
"args": {
"required": ["propA1", "propA2"]
}
}
}, {
"properties": {
"type": {"enum": ["b"]},
"args": {
"required": ["propB1"]
}
}
}, {
"properties": {
"type": {"enum": ["c"]},
"args": {
"required": ["propC1", "propC2"]
}
}
}]
},
"required": ["type", "args"]

Related

JSON Schema - How to narrow down possible array object values

How can the following requirements be configured in a JSON schema.
I have the following JSON
{
"orderMethods": [
{
"requestType": "some service",
"deployType": "MANUAL",
"deployLabel": "some label"
},
{
"requestType": "some service",
"deployType": "MANUAL",
"deployLabel": "some label"
},
{
"requestType": "some service",
"deployType": "AUTO",
"deploySubType": "REST",
"deployLabel": "some label",
"deployConfig": "some config"
},
{
"requestType": "some service",
"deployType": "AUTO",
"deploySubType": "DB",
"deployLabel": "some label",
"deployConfig": "some config"
}
]
}
Requirements:
only one deployType = "MANUAL" is allowed
only one deployType = "AUTO" is allowed
additionally, only one deploySubType = "REST or "DB" is allowed
Currently I have the following JSON schema. Unfortunately the above JSON is valid. How can the above requirements be addressed?
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"properties": {
"orderMethods": {
"$ref": "#/definitions/OrderMethods"
}
},
"additionalProperties": false,
"definitions": {
"OrderMethods": {
"type": "array",
"items": {
"$ref": "#/definitions/OrderMethod"
}
},
"OrderMethod": {
"oneOf": [
{
"$ref": "#/definitions/OrderMethodManualDeploy"
},
{
"$ref": "#/definitions/OrderMethodAutoDeploy"
}
],
"uniqueItems": true
},
"OrderMethodAutoDeploy": {
"oneOf": [
{
"$ref": "#/definitions/OrderMethodAutoRestDeploy"
},
{
"$ref": "#/definitions/OrderMethodAutoDBDeploy"
}
],
"uniqueItems": true
},
"OrderMethodManualDeploy": {
"type": "object",
"properties": {
"requestType": {
"type": "string"
},
"deployType": {
"const": "MANUAL"
},
"deployLabel": {
"type": "string"
}
},
"required": [
"requestType",
"deployType",
"deployLabel"
],
"additionalProperties": false
},
"OrderMethodAutoRestDeploy": {
"type": "object",
"properties": {
"requestType": {
"type": "string"
},
"deployType": {
"const": "AUTO"
},
"deploySubType": {
"const": "REST"
},
"deployLabel": {
"type": "string"
},
"deployConfig": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"requestType",
"deployType",
"deploySubType",
"deployLabel",
"deployConfig"
]
},
"OrderMethodAutoDBDeploy": {
"type": "object",
"properties": {
"requestType": {
"type": "string"
},
"deployType": {
"const": "AUTO"
},
"deploySubType": {
"const": "DB"
},
"deployConfig": {
"type": "string"
},
"deployLabel": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"requestType",
"deployType",
"deploySubType",
"deployLabel",
"deployConfig"
]
}
}
}
Thanks for your help/ideas.

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

Is it possible to create schema references that are sometimes nullable and sometimes not?

I have a schema that re-uses an object type quite a lot, and I'd like to extract that type into $defs. However, I sometimes need it to be nullable, and sometimes not. Is there a good way to achieve this?
Example schema with all the duplication:
{
"type": "object",
"properties": {
"foo": {
"type: "object",
"properties: {
"a": { "type": "string" },
"b": { "type": ["string", "null"] },
"c": { "type": ["string", "null"] }
},
"required": ["a"],
"additionalProperties": false
},
"bar": {
"type: "object",
"properties: {
"a": { "type": "string" },
"b": { "type": ["string", "null"] },
"c": { "type": ["string", "null"] }
},
"required": ["a"],
"additionalProperties": false
},
"baz": {
"type: ["object", "null"],
"properties: {
"a": { "type": "string" },
"b": { "type": ["string", "null"] },
"c": { "type": ["string", "null"] }
},
"required": ["a"],
"additionalProperties": false
}
}
}
I can get almost all the way with something like
{
"type": "object",
"properties": {
"foo": { "$ref": "#/$defs/abc" },
"bar": { "$ref": "#/$defs/abc" },
"baz": { "$ref": "#/$defs/abc" }
},
"$defs": {
"abc": {
"type: "object",
"properties: {
"a": { "type": "string" },
"b": { "type": ["string", "null"] },
"c": { "type": ["string", "null"] }
},
"required": ["a"],
"additionalProperties": false
}
}
}
however, now baz is not nullable. How can I achieve maximum re-usability of the properties definitions etc, but with variable nullability?
Nulls are weird in JSON, so there's a little ambiguity here. In most languages, null means there is nothing there. In JSON, the equivalent is "undefined". A value is undefined if it doesn't exist in the JSON. Null in JSON is a different concept where the value exists and it's type is "null". The "null" type consists of the singleton value null and is not equivalent to undefined.
So, when you talk about nullability, I'm assuming you mean "null" or undefined because that's how your schemas are written. If you have a choice, I'd recommend not to use null in JSON and leave out values that have no value instead.
JSON Schema doesn't have a way to remove constraints, so you have to define your definitions a little leaner to facilitate composition. "type": ["object", "null"] is sugar for "anyOf: [{ "type": "object" }, { "type": "null" }]. Once you break that down, you end up with a small enough unit to facilitate the composition you require.
{
"type": "object",
"properties": {
"foo": { "$ref": "#/$defs/abc" },
"bar": { "$ref": "#/$defs/abc" },
"baz": {
"anyOf": [
{ "$ref": "#/$defs/abc" },
{ "type": "null" }
]
}
},
"$defs": {
"abc": {
"type: "object",
"properties: {
"a": { "type": "string" },
"b": { "type": ["string", "null"] },
"c": { "type": ["string", "null"] }
},
"required": ["a"],
"additionalProperties": false
}
}
}

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