How to use JSON Schema to require one of two fields - json

I want to validate JSON to make one of two fields manadatory.
Let's assume we have two fields (Email Address and Phone Number). I want to make sure that one of the two fields is required for the record to be valid.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "ExampleID-0212",
"title": "objectExamples",
"description": "Demo",
"type": "object",
"properties": {
"RecordObject": {
"type": "object",
"properties": {
"emailAddress": {
"type": "string"
},
"PhoneNumber": {
"type": "number"
}
}
}
},
"required": [
"RecordObject"
]
}

You need to add:
"anyOf": [
{ "required":
[ "emailAddress" ] },
{ "required":
[ "PhoneNumber" ] }
]
to the schema of RecordObject property.
It requires that at least one of fields is present. If you need exactly one field (i.e., not both) present, you need to use "oneOf" keyword (the rest should be the same).
This reference of JSON Schema keywords can be useful.

Sooperb Answer from ESP.. that is from jsonSchema ...
you can also do that validation thorugh condition..see below
if(EmailAddress == null && PhoneNumber == null){
//statements or error message response
}

Related

How to make a required property if another property is empty and vice versa, in the JSON Schema

My current json schema definition is like this
{
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"description": {
"type": "string",
"minLength": 1
},
"input": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": ["name", "description", "type"]
}
},
"output": {
"type": "array",
"maxItems": 1,
"items": {
"type": "object",
"properties": {
"description": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string"
}
},
"required": ["description", "type"]
}
}
},
"required": ["name", "description"]
}
So I need to validate the scheme for the following conditions:
If input array and output array are empty, both must be required;
If the input array is not empty, then the output array should not be required;
If the output array is not empty, then the input array should not be required;
Thank you in advance.
Your first condition is the only one that we need to deal with. All properties are optional by default, so your conditions 2 and 3 translate to something like, "if the input array is not empty, then do nothing".
There are a couple of ways to achieve the first condition, but I suggest the following.
"allOf": {
"if": {
"properties": {
"input": { "const": [] },
"output": { "const": [] }
}
},
"then": { "required": ["input", "output"] }
}
it seems like all three of your requirements are self-fulfilling in json schema.
If input array and output array are empty, both must be required
if input and output are empty arrays, they are already present, so saying they are required is redundant. sort of, "if x is present with the value [], then x must be present". Jason's schema correctly expresses the way you've phrased this, but I don't think there's any way for that schema to cause a validation error.
and Jason's answer is correct on points 2 and 3.
I'd suggest you think about some example instances you would expect to fail validation (and add them to your question here), and that will help to construct a schema that adds the proper constraints.

Using multiple anyOf inside oneOf

I wanted to create a schema where I will be having multiple objects inside "oneOf" which will be having many objects in anyOf format where some of the keys can be of required type(this part works)
My schema :-
{
"description": "schema v6",
"type": "object",
"oneOf": [
{
"properties": {
"Speed": {
"items": {
"anyOf": [
{
"$ref": "#/definitions/speed"
},
{
"$ref": "#/definitions/SituationType"
}
]
},
"required": [
"speed"
]
}
},
"additionalProperties": false
}
],
"definitions": {
"speed": {
"description": "Speed",
"type": "integer"
},
"SituationType": {
"type": "string",
"description": "Situation Type",
"enum": [
"Advice",
"Depend"
]
}
}
}
But when I'm trying to verify this schema but i'm able to authenticate some incorrect values like
{
"Speed": {
"speed": "ABC",//required
"SituationType1": "Advisory1" //optional but key needs to be correct
}
}
correct response which i was expecting was
{
"Speed": {
"speed": "1",
"SituationType": "Advise"
}
}
First, you need to set the schema type correctly, otherwise implmentations may assume you're using the latest JSON Schema version (currently draft-7).
So, in your schema root, you need the following:
"$schema": "http://json-schema.org/draft-06/schema#",
Second, items is only applicable if the target is an array.
Currently your schema only checks the following:
If the root object has a property of "Speed", it must have a key of
"speed". The root object must not have any other properties.
And nothing else.
Your use of definitions and how you reference them is probably not what you intended.
It looks like you want Speed to contain speed which must be an integer, and optionaly SituationType which must be a string, limited by enum, and nothing else.
Here's the schema I have based on that, which passes and fails correctly based on your given example data:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"type": "object",
"oneOf": [
{
"properties": {
"Speed": {
"properties":{
"speed": {
"$ref": "#/definitions/speed"
},
"SituationType": {
"$ref": "#/definitions/SituationType"
}
},
"required": [
"speed"
],
"additionalProperties": false
}
},
"additionalProperties": false
}
],
"definitions": {
"speed": {
"description": "Speed",
"type": "integer"
},
"SituationType": {
"type": "string",
"description": "Situation Type",
"enum": [
"Advice",
"Depend"
]
}
}
}
You need to define the properties for Speed, because otherwise you can't prevent additional properties, as additionalProperties is only effected by adjacent an properties key. We are looking to created a new keyword in draft-8 to support this kind of behaviour, but it doesn't look like you need it in your example (Huge Github issue in relation).
Adding additionalProperties false to the Speed schema now prevents other keys in that object.
I SUSPECT that given your question title, there may be more schema at play here, and you've simplified it for this question. If you have a more detailed schema with more complex issues, I'd be happy to help also.

JSON Schema check entire json for certain property with null values

I'm trying to write a json schema that searches any json with different structures for all occurences of a certain property called "field_name" and checks if that property has a value. There can't be an empty "field_name".
The property "field_name" can be at any level in the json file, e.g
https://raw.githubusercontent.com/stopopol/deims_apps/master/metadata_models/smm.json
So far I have this, but it never complains when a "field_name" is empty.
{
"$schema": "http://json-schema.org/schema#",
"title": "Metadata Model",
"type": "object",
"required": [
"name",
"abbreviation",
"version",
"releaseDate",
"scope",
"content"
],
"patternProperties": {
"field_name": {
"type": "string",
"minLength": 1
}
}
}
I thought that I could just check for any occurence of property "field_name" and that it needs to be a string with a lenght of at least 1.
You can do this with a surprisingly simple recursive schema. The properties and additionalProperties keywords only apply when the data being validated is an object. If the data is not an object, these keywords get ignored. This allows us to express the "if the value is an object" part simply by leaving out the "type": "object" declaration.
The use of allOf/definitions shows how to express the recursive constraint without making the entire schema recursive.
{
"title": "Metadata Model",
"type": "object",
"required": [
"name",
"abbreviation",
"version",
"releaseDate",
"scope",
"content"
],
"allOf": [{ "$ref": "#/definitions/field_name-not-empty-deep" }],
"definitions": {
"field_name-not-empty-deep": {
"properties": {
"field_name": {
"type": "string",
"minLength": 1
}
},
"additionalProperties": { "$ref": "#/definitions/field_name-not-empty-deep" }
}
}
}
{
"anyOf" :
[
{
"not" :
{
"type" : "object"
}
},
{
"properties" :
{
"field_name" :
{
"not" :
{
"type" : "null"
}
}
},
"additionalProperties" :
{
"$ref" : "#"
}
}
]
}
Each instance encountered is either not an object OR it checks for your property not being null, then it runs the filter on all other properties (this is done using the $ref which points to the root object) in turn applying this recursively on all possible sub-objects.
(I assume by "empty" you mean the property is set and equal to null.)

JSON schema verification

I have to create a form using JSON.
So as a first step i need to verify JSON with schema.
Here is a part of my JSON
"elements":{
"textbox":{
"name":{
"type":"text",
"name":"textbox",
"label":"Enter Your Name",
"required":false,
"disabled":false,
"maxlength":"",
"pattern":"",
"readonly":false,
"value":"",
"autocomplete":"off"
},
"school":{
"type":"text",
"name":"textbox",
"label":"F",
"required":false,
"disabled":false,
"maxlength":"",
"pattern":"",
"readonly":false,
"value":"",
"autocomplete":"off"
}
...
...
...
}
So inside "elements", it has a textbox, and one who types in the JSON can give any number of textbox field inside "textbox" for the form creation.
I need to write a JSON Schema to verify the data i.e, specifically i need to know how to do for this particular elements part. To define it as an array inside array or object..?? :( :/
Well, I do suggest that you define textbox as an array. This way, you could set different parameters for the objects in your array and then you would be able to verify the data this way.
Here is a little example of what I am talking about:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {},
"id": "example",
"properties": {
"elements": {
"id": "/properties/elements",
"properties": {
"textbox": {
"id": "/properties/elements/properties/textbox",
"items": {
"id": "/properties/elements/properties/textbox/items",
"properties": {
"Parameter1": {
"id": "/properties/elements/properties/textbox/items/properties/Parameter1",
"type": "string"
},
"Parameter2": {
"id": "/properties/elements/properties/textbox/items/properties/Parameter2",
"type": "number"
},
"Parameter3": {
"id": "/properties/elements/properties/textbox/items/properties/Parameter3",
"type": "integer"
}
},
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
},
"type": "object"
}
This way, the user can input as many textboxes he wants and you can still use the same schema to verify the JSON.

JSON Hyper-Schema: different schemas for GET and POST

I want to describe an API that has fields which allows for different ways to define values when POSTing an item, but only ever output in the field in one specific way.
For example, I might want to describe an API where an item can be created or updated like this: {"name": "Task", "due": "2014-12-31"} or like this: {"name": "Task", "due": {"$date": 1419984000000}}, but it is only ever returned from the API in the first way.
The schema for POST/PUT could therefore be:
{
"type": "object"
"properties": {
"name": {
"type": "string"
},
"due": {
"oneOf": [
{
"type": "string",
"format": "date"
},
{
"type": "object",
"properties": {
"$date": {
"type": "number"
}
},
"required": ["$date"],
"additionalProperties": false
}
]
}
}
}
Whereas the schema for access via GET would be much simpler:
{
"type": "object"
"properties": {
"name": {
"type": "string"
},
"due": {
"type": "string",
"format": "date"
}
}
}
It would be good for consumers of the API to know that they only have to account for one possible output method rather then all of them.
Is there any accepted standard approach to specify the different schemas within the context of JSON Hyper-Schema? I've thought about specifying these differences via the "links" property, but I do not know what "rel" I would define these schemas under and it seems very-non-standard.
If I understood correctly, and you want to specify one schema per operation you can do it with standard hyper-schema. Let's see and example for a post operation:
{
"description": "create an item.",
"href": "/items",
"method": "POST",
"rel": "create",
"schema": {
"$ref": "#/api/createitem"
},
"title": "Create an item"
}
The actual schema that is required is referenced in "schema" property through "$ref".
If you also wanted to describe the response types, then you could use "targetSchema" property. Be aware that this is advisory only (as it is explained in the docs)