How to prevent certain fields based on another fields value with JSON Schema validator - jsonschema

Depending on the salaryRange the user selects I need to validate differently by requiring some fields and rejecting others. I feel like its a combination of allOf and not but I can't seem to quite get it.
Scenario #1
User selects salaryRange(Hourly)
Require hourlyRate
Prevent the submission of fields feeOne and feeTwo
Scenario #2
User selects salaryRange(0-50k OR 50-100k)
Require feeOne and feeTwo
Prevent the submission of field hourlyRate
Here is my schema
{
"schema": "http://json-schema.org/draft-04/schema#",
"$id": "http://mysite/schemas/job.json#",
"title": "Job",
"description": "Create job",
"type": "object",
"properties": {
"title": { "type": "string" },
"description": { "type": "string" },
"salaryRange": { "enum": ["0-50k", "50-100k", "100-150k", "150-200k", "200-300k", "300k+", "nonExempt", "Hourly"] },
"hourlyRate": {
"type": "number",
"minimum": 0,
"maximum": 300
},
"feeOne": {
"type": "number",
"minimum": 0
},
"feeTwo": {
"type": "number",
"minimum": 0
}
} ,
"additionalProperties": false,
"required": [
"title",
"description",
"salaryRange"
]
}

You can use oneOf and not required to model all possible combinations.
Here is an example in js:
https://runkit.com/embed/cf8cra1mwvx3/
{
"schema": "http://json-schema.org/draft-04/schema#",
"$id": "http://mysite/schemas/job.json#",
"title": "Job",
"description": "Create job",
"type": "object",
"properties": {
"title": { "type": "string" },
"description": { "type": "string" },
"salaryRange": { "enum": ["0-50k", "50-100k", "100-150k", "150-200k", "200-300k", "300k+", "nonExempt", "Hourly"] },
"hourlyRate": {
"type": "number",
"minimum": 0,
"maximum": 300
},
"feeOne": {
"type": "number",
"minimum": 0
},
"feeTwo": {
"type": "number",
"minimum": 0
}
},
"oneOf": [
{
"description": "Disallow fees for hourly salary",
"properties": {
"salaryRange": { "enum": ["Hourly"] }
},
"required": ["hourlyRate"],
"allOf": [
{"not":{"required":["feeOne"]}},
{"not":{"required":["feeTwo"]}}
]
},
{
"description": "Disallow hourly rate for 0-50k, 50-100k salaries",
"properties": {
"salaryRange": { "enum": ["0-50k", "50-100k"] }
},
"required": ["feeOne", "feeTwo"],
"not":{"required":["hourlyRate"]}
},
{
"description": "Allow other cases",
"properties": {
"salaryRange": { "not" : {"enum": ["Hourly", "0-50k", "50-100k"] } }
}
}
],
"additionalProperties": false,
"required": [
"title",
"description",
"salaryRange"
]
}

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.

Validate a property value against another property value

Take the following schema:
{
"properties": {
"StageHEP": {
"description": "The stage of hepatitis",
"type": "string",
"enum": ["ACUTE", "CHRONIC", "UNK"]
},
"complications": {
"description": "Disease complications",
"type": "string",
"enum: ["CIRR", "CANCER", "NONE", "UNK"]
}
}
}
I want to create a validation rule (within the schema) that states that:
if StageHEP = ACUTE, complications property cannot be CIRR
Is it possible with json-schema draft v4?
You can do it using "oneOf":
{
"oneOf": [
{
"properties": {
"StageHEP": {
"description": "The stage of hepatitis",
"type": "string",
"enum": [
"CHRONIC",
"UNK"
]
},
"complications": {
"description": "Disease complications",
"type": "string",
"enum": [
"CIRR",
"CANCER",
"NONE",
"UNK"
]
},
"additionalProperties": false
}
},
{
"properties": {
"StageHEP": {
"description": "The stage of hepatitis",
"type": "string",
"enum": [
"ACUTE"
]
},
"complications": {
"description": "Disease complications",
"type": "string",
"enum": [
"CANCER",
"NONE",
"UNK"
]
},
"additionalProperties": false
}
}
]
}

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