Json Schema: Require a property only when a specific property is present - json

good day everyone, I am new here,
I have a json response looking like this
{
"Number": "20.09.00001",
"Supplier": {
"Name": "John Doe",
"Title": "Mr.",
"FirstName": "John",
"LastName": "Doe",
"Phone": "0212341234",
"Email": "foobar#gmail.com",
"Code": "Foo123",
"Gender": "Male"
}
}
I want to make inside the supplier properties required so I make a JSON schema validation looking like this
{
"type": "object",
"required": [
"Supplier"
],
"properties": {
"Supplier": {
"type": "object",
"required": [
"Name",
"Title",
"FirstName",
"LastName",
"Phone",
"Email",
"Code",
"Gender"
],
"properties": {
"Name": {
"type": "string"
},
"Title": {
"type": "string"
},
"FirstName": {
"type": "string"
},
"LastName": {
"type": "string"
},
"Phone": {
"type": "string"
},
"Email": {
"type": "string"
},
"Code": {
"type": "string"
},
"Gender": {
"type": "string"
}
}
}
}
}
but the problem is, the inside of supplier properties are not always present, when it's not supplied, it will only return empty objects like this
{
"Number": "20.09.00001",
"Supplier": {}
}
how can I validate only IF the inside supplier returns full property object, and ignore if the supplier returns an empty object?
I have tried using if else and anyOff but resulting in no luck.
my code with if else that did not work:
"Supplier": {
"type": ["object"],
"if": {
"properties": {
"Name": {
"type": ["string", "null"]
},
"Title": {
"type": ["string", "null"]
},
"FirstName": {
"type": ["string", "null"]
},
"LastName": {
"type": ["string", "null"]
},
"Phone": {
"type": ["string", "null"]
},
"Email": {
"type": ["string", "null"]
},
"Code": {
"type": ["string", "null"]
},
"Gender": {
"type": ["string", "null"]
}
}
},
"then": {
"required": [
"Name",
"Title",
"FirstName",
"LastName",
"Phone",
"Email",
"Code",
"Gender"
]
},
"else": {
"required": []
}
}

I think anyOf is the best approach in this case. The object is either empty or all the properties are required. There are a couple of way to assert that an object is empty. You could use "maxProperties": 0 or "const": {}.
{
"type": "object",
"properties": {
... all your properties ...
},
"anyOf": [
{ "const": {} },
{ "required": [ ... all required properties ... ] }
]
}

Related

Create a recursive json schema which is generic

I am trying to create a json schema for a json file. The structure of the json is generic and I am trying to create a generic schema for json files which contain a similar structure to the one shown below.
**Json file:**
{
"Soccer League": {
"lvl": "Championships",
"state": "1",
"Clubs": {
"Rosely": {
"Boys": {"id": "A1", "state": "Ready"},
"Girls": {
"id": "A2",
"state": "Ready",
"Substitutes": {
"id": "A3",
"state": "Sitting",
"Goalkeepers": {
"Players": {"id": "A4", "state": "Idle"},
"id": "A5",
"state": "Idle",
},
},
},
},
"Division League": {
"TeamA": {
"PlayersA": {
"id": "A6",
"status": "Ready",
"CoachA": {"id": "A7", "state": "Ready"},
},
"PlayersB": {
"id": "A8",
"state": "Playing",
"CoachB": {"id": "A9", "state": "Idle"},
},
}
},
},
}
}
**Json-schema:**
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Soccer League": {
"type": "object",
"properties": {
"lvl": {
"type": "string"
},
"state": {
"type": "string"
},
"Clubs": {
"type": "object",
"properties": {
"Rosely": {
"type": "object",
"properties": {
"Boys": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"state": {
"type": "string"
}
},
"required": [
"id",
"state"
]
},
"Girls": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"state": {
"type": "string"
},
"Substitutes": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"state": {
"type": "string"
},
"Goalkeepers": {
"type": "object",
"properties": {
"Players": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"state": {
"type": "string"
}
},
"required": [
"id",
"state"
]
},
"id": {
"type": "string"
},
"state": {
"type": "string"
}
},
"required": [
"Players",
"id",
"state"
]
}
},
"required": [
"id",
"state",
"Goalkeepers"
]
}
},
"required": [
"id",
"state",
"Substitutes"
]
}
},
"required": [
"Boys",
"Girls"
]
},
"Division League": {
"type": "object",
"properties": {
"TeamA": {
"type": "object",
"properties": {
"PlayersA": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"status": {
"type": "string"
},
"CoachA": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"status": {
"type": "string"
}
},
"required": [
"id",
"status"
]
}
},
"required": [
"id",
"status",
"CoachA"
]
},
"PlayersB": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"status": {
"type": "string"
},
"CoachB": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"status": {
"type": "string"
}
},
"required": [
"id",
"status"
]
}
},
"required": [
"id",
"status",
"CoachB"
]
}
},
"required": [
"PlayersA",
"PlayersB"
]
}
},
"required": [
"TeamA"
]
}
},
"required": [
"Rosely",
"Division League"
]
}
},
"required": [
"lvl",
"state",
"Clubs"
]
}
},
"required": [
"Soccer League"
]
}
As we can see from above, we have many same layers but just with different names. I am unsure on how to create a recursive json schema for json files which will follow a similar format. This is sort of hard-coded, but how to make it generic.
I am new to json schema and would appreciate if someone could help me infer a schema from the json above. Any help would be greatly appreciated.

JSON Schema not validating required field when it is an empty string

I'm using mule validate JSON schema component to validate my incoming json request.
It validates the type but not the required field attributes
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"properties": {
"Employees": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"BirthDate": {
"type": "string",
"format": "date-time"
},
"EmpNum": {
"type": "number"
},
"FirstName": {
"type": "string"
},
"Gender": {
"type": "string"
},
"LastName": {
"type": "string"
},
"LicenseNumber": {
"type": "string"
},
"ZipCode": {
"type": "string"
}
},
"required": ["EmpNum", "LastName", "FirstName", "Street", "ZipCode", "BirthDate" ]
}
}
}
}
I have json as shown below:
{
"Employees": [
{
"EmpNum": 3,
"FirstName": "Finder",
"LastName": "Path",
"Street": "392 CDI CDIJUW",
"ZipCode": "12345",
"BirthDate": "1943-05-19T04:00:00Z",
"Gender": "M"
},
{
"EmpNum": 3,
"FirstName": "",
"LastName": "Path",
"Street": "392 CDI CDIJUW",
"ZipCode": "12345",
"BirthDate": "1943-05-19T04:00:00Z",
"Gender": "M"
}
]
}
Even though I have set a field to an empty string, it still takes as a valid request and proceeds further.
If you intentionally set FirstName to be an empty string and want to invalidate it, try adding minLength:
"FirstName": {
"type": "string",
"minLength": 1
},

I want to validate the following JSON schema in datapower using schema file

{
"email": "005foobar#gmail.com",
"phone": "9867534210",
"country_code": "91",
"firstname":"Rakesh",
"surname" :"A R"
}
I want either firstname or surname to be in my request(like one of: "firstname" or "surname")
For example:
{
"email": "005foobar#gmail.com",
"phone": "9867534210",
"country_code": "91",
"firstname":"Rakesh"
}
or
{
"email": "005foobar#gmail.com",
"phone": "9867534210",
"country_code": "91",
"surname":"A R"
}
Can you please help me with the json schema for my requirement?
For example something like this. It is a little bit complex, but if you want exactly EITHER surname OR fisrtName but NOT together and NOT absence of them it is what you need.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"email": {
"type": "string"
},
"phone": {
"type": "string"
},
"country_code": {
"type": "string"
}
},
"type": "object",
"oneOf": [
{
"properties": {
"email": {
"$ref": "#/definitions/email"
},
"phone": {
"$ref": "#/definitions/phone"
},
"county_code": {
"$ref": "#/definitions/country_code"
},
"firstname": {
"type": "string"
}
},
"required": [
"email",
"phone",
"country_code",
"firstname"
]
},
{
"properties": {
"email": {
"$ref": "#/definitions/email"
},
"phone": {
"$ref": "#/definitions/phone"
},
"county_code": {
"$ref": "#/definitions/country_code"
},
"surname": {
"type": "string"
}
},
"required": [
"email",
"phone",
"country_code",
"surname"
]
}
]
}

JSON-Schema: Conditional dependency (by value)

This is the simplified JSON-Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "user",
"type": "object",
"properties": {
"account": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["COMPANY", "PERSON"]
}
},
"required": ["type"]
},
"person": {
"type": "object",
"properties": {
"firstName": { "type": "string" },
"lastName": { "type": "string" }
},
"required": ["firstName", "lastName"]
},
"company": {
"type": "object",
"properties": {
"name": { "type": "string" },
"taxNumber": { "type": "string" }
}
}
},
"required": ["account", "person"]
}
What I want to achieve is:
If account.type is set to "COMPANY":
company object and its properties should be required.
If account.type isset to "PERSON":
company object should be optional.
But if company object is present, company.name and company.taxNumber should be required.
This can be achieved by defining two long sub-schemas under a oneOf but that would mean too many duplicates and a complex schema, since account and company has many more properties than this simplified version.
AFAIK, the only way to define a specific value in a schema is by using the enum keyword with a single item. I tried this with the dependencies keyword but didn't help.
Can you think of a way without altering the structure of the data object?
You can express this requirement using switch keyword from JSON-schema v5/6 proposals that is supported in Ajv (I am the author).
Under Draft-07, you can do it by conditionally applying schema requirements:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"id": "user",
"type": "object",
"properties": {
"account": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["COMPANY", "PERSON"]
}
},
"required": ["type"]
},
"person": {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
}
},
"required": ["firstName", "lastName"]
},
"company": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"taxNumber": {
"type": "string"
}
}
}
},
"if": {
"properties": {
"account": {
"const": {
"type": "COMPANY"
}
}
}
},
"then": {
"required": ["account", "person", "company"]
},
"else": {
"required": ["account", "person"]
}
}
Here's a working example that validates against it:
{
"account": {
"type": "COMPANY"
},
"person": {
"firstName": "John",
"lastName": "Doe"
},
"company": {
"name": "XYZ Corp"
}
}

JSON Schema: Require properties on an optional object type

I have defined a customer object type in my json schema:
"customer": {
"type": "object",
"properties": {
"id": { "type": "string" },
"first_name": { "type": "string" },
"last_name": { "type": "string"},
"email": { "type": "string" },
"billing_address": { "$ref": "#\/definitions\/street_address" },
"shipping_address": { "$ref": "#\/definitions\/street_address" },
},
"required": [ "id", "first_name", "last_name", "email", "billing_address"]
},
I would like to validate shipping_address (optional object) if it is sent and reject it if it is missing the required fields. Here is the street_address object definition:
"street_address": {
"type": "object",
"properties": {
"first_name": {"type": "string" },
"last_name": { "type": "string" },
"address": { "type": "string" },
"address2": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"zip_code": { "type": "string"},
"country_code": { "type": "string"},
"phone": { "type": "string"},
"fax": {"type": "string"}
},
"required": [
"first_name",
"last_name",
"address",
"city",
"state",
"zip_code",
"country_code"
]
},
How do I configure my JSON schema to accomplish this? When I send a shipping address now, the fields inside the object do not get validated.
You are using the reference "$ref": "#\/definitions\/street_address" (btw, you dont have to escape the slashes). In that case the street_address definition must be in in the same document, inside the "defintions" node. So your schema file looks like this
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "customer",
"type": "object",
"properties": {
"id": { "type": "string" },
"first_name": { "type": "string" },
"last_name": { "type": "string"},
"email": { "type": "string" },
"billing_address": { "$ref": "#/definitions/street_address" },
"shipping_address": { "$ref": "#/definitions/street_address" },
},
"required": [ "id", "first_name", "last_name", "email", "billing_address"],
"definitions" : {
"street_address" : {
/* here comes the street_address definition */
},
/* other entity definitions */
}
}
I'm using the nodejs module jayschema (see https://github.com/natesilva/jayschema) for validation, and it works fine that way.