Json Schema different input formats - json

I'm creating some models in AWS API Gateway. I'm having problems with one that I wish it receives 2 input formats: one of the formats is just a dictionary the other is an array of dictionaries:
{
"id":"",
"name":""
}
and
[
{
"id":"",
"Family":""
},
{
"id":"",
"Family":""
},
...
{
"id":"",
"Family":""
}
]
Until now I've created the model to accept only the dictionary way:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Update",
"type": "object",
"properties": {
"id": { "type": "string"},
"name": { "type": "string"}
},
"required": ["id"]
}
Can you give me some tips to create the array of dictionaries, please. I've done some research and I found nothing but I'm following the way of the keywords oneOf and anyOf but I'm not sure.

You're on the right track with anyOf. What you should do depends on the similarity between the object (dictionary) that's by itself and the object that's in the array. They look different in your example, so I'll answer in kind, then show how to simplify things if they are in fact the same.
To use anyOf, you want to capture the keywords that define your dictionary
{
"type": "object",
"properties": {
"id": { "type": "string"},
"name": { "type": "string"}
},
"required": ["id"]
}
and wrap that inside an anyOf right at the root level of the schema
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Update",
"anyOf": [
{
"type": "object",
"properties": {
"id": { "type": "string"},
"name": { "type": "string"}
},
"required": ["id"]
}
]
}
To write a schema for an array of the same kind object, you need the items keyword.
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string"},
"Family": { "type": "string"}
},
"required": ["id"]
}
}
Add this in as a second element in the anyOf array, and you're golden.
If your lone object can have the same schema as your array-element object, then you can write that schema once as a definition and reference it in both places.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Update",
"definitions": {
"myObject": {
"type": "object",
"properties": {
"id": { "type": "string"},
"name": { "type": "string"}
},
"required": ["id"]
}
},
"anyOf": [
{ "$ref": "#/definitions/myObject" },
{
"type": "array",
"items": { "$ref": "#/definitions/myObject" }
}
]
}

Related

JSON Schema for child objects with different set of keys

I have JSON data of which is an array of data like
[
{
"type": "background_color",
"data": {
"backgroundColor": "F9192D"
}
},
{
"type": "banner_images",
"data": {
"images": [
{
"url": "https://example.com/abc.jpg",
"id": 3085
},
{
"url": "https://example.com/zyx.jpg",
"id": 3086
}
]
}
},
{
"type": "description_box",
"data": {
"text": "Hello 56787"
}
}
]
The data is an array of object which has two keys type and data. The type and keys of the data will be defined by the type of data it has.
Like for background_color type, the data should have backgroundColor property, while for banner_images, data should have images which is an array of other properties.
Till now, What I have done is
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"title": "category schema",
"description": "Used to validate data of category",
"examples": [],
"required": [],
"items": {
"type": "object",
"required": [
"type",
"data"
],
"properties": {
"type": {
"type": "string",
"enum": ["background_color", "banner_images", "description_box"]
},
"data": {
"type": "object" // How to define data property here for each use case
}
}
}
}
I'm not getting how to define the data property for each use case?
You can use if/then/else blocks to define conditional constraints.
The values of if and then are schemas. If the if schema is valid, then the then schema is applied, otherwise, the allOf subschema (allOf[0] in this example) would pass validation.
There are a few different ways to do this, but this is clean when you don't have any additional or special requirements. Please come back if you do =]
In this example, I've added banner_images...
You can test it working here.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"title": "category schema",
"description": "Used to validate data of category",
"items": {
"type": "object",
"required": [
"type",
"data"
],
"properties": {
"type": {
"type": "string",
"enum": [
"background_color",
"banner_images",
"description_box"
]
},
"data": {
"type": "object"
}
},
"allOf": [
{
"if": {
"properties": {
"type": {
"const": "banner_images"
}
}
},
"then": {
"properties": {
"data": {
"required": [
"images"
],
"properties": {
"images": {
"type": "array"
}
}
}
}
}
}
]
}
}
For reference, here's the part of the JSON Schema draft-7 spec document that details the behaviour: https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.6

JSON Schema if-else condition complex scenario

{
"policyHolder": {
"fullName": "A"
},
"traveller": [
{
"fullName": "B",
"relationship": "Spouse"
},
{
"fullName": "A",
"relationship": "My Self"
}
]
}
In above json, I want to validate that
if "relationship" = "My Self" then fullName must match the fullName in policyHolder
A field relationship must exist in traveller array, else json is invalid
I have tried to create a json schema with if-else, allOf, etc. but nothing works which can do these validations but not able to.
Please help!!
Schema:
{
"type": "object",
"required": [
"policyHolder",
"traveller",
],
"properties": {
"policyHolder": {
"$id": "#/properties/policyHolder",
"type": "object",
"required": [
"fullName"
],
"properties": {
"fullName": {
"$id": "#/properties/policyHolder/properties/fullName",
"type": "string",
}
}
},
"traveller": {
"$id": "#/properties/traveller",
"type": "array",
"minItems": 1,
"items": {
"$id": "#/properties/traveller/items",
"type": "object",
"properties": {
"fullName": {
"$ref": "#/properties/policyHolder/properties/fullName"
},
"relationship": {
"$id": "#/properties/traveller/items/properties/relationship",
"type": "string",
}
},
"required": [
"fullName",
"relationship"
],
}
}
}
}```
It's your first requirement that you're going to have the most trouble with. JSON Schema doesn't support validation of data against data elsewhere in the instance. It's a highly discussed topic, but nothing has been adopted yet. I suggest you verify this with a little code.
For the second, I would suggest you extract some of your subschemas into definitions rather than trying to muck about with IDs. IDs are typically more beneficial if you're referencing them from other documents or if you use short (like single-word) IDs. Defining the ID as its location in the document is redundant; most processors will handle this automatically.
{
"type": "object",
"required": [
"policyHolder",
"traveller",
],
"definitions": {
"person": {
"type": "object"
"properties": {
"fullName": {"type": "string"}
},
"required": ["fullName"]
},
"relationship": { "enum": [ ... ] } // list possible relationships
},
"properties": {
"policyHolder": { "$ref": "#/definitions/person" },
"traveller": {
"type": "array",
"minItems": 1,
"items": {
"allOf": [
{ "$ref": "#/definitions/person" },
{
"properties": {
"relationship": { "$ref": "#/definitions/relationship" }
},
"required": ["relationship"]
}
]
}
}
}
}
(I extracted the relationship into its own enum definition, but this is really optional. You can leave it inline, or even an unrestricted string if you don't have a defined set of relationships.)
This can't currently be done with JSON Schema. All JSON Schema keywords can only operate on one value at a time. There's a proposal for adding a $data keyword that would enable doing this kind of validation, but I don't think it's likely to be adopted. $data would work like $ref except it references the JSON being validated rather than referencing the schema.
Here's what how you would solve your problem with $data.
{
"type": "object",
"properties": {
"policyHolder": {
"type": "object",
"properties": {
"fullName": { "type": "string" }
}
},
"traveler": {
"type": "array",
"items": {
"type": "object",
"properties": {
"fullName": { "type": "string" },
"relationship": { "type": "string" }
},
"if": {
"properties": {
"relationship": { "const": "My Self" }
}
},
"then": {
"properties": {
"fullName": { "const": { "$data": "#/policyHolder/fullName" } }
}
}
}
}
}
}
Without $data, you will have to do this validation in code or change your data structure so that it isn't necessary.

JSON Schema: Using anyOf, oneOf, allOf within additionalProperties

I am trying to validate an object that can have arbitrary keys whose values are either an object that looks like:
{ "href": "some string" }
OR an array containing object's matching the above.
Here is what I currently have and DOES NOT WORK:
{
"$schema": "http://json-schema.org/schema#",
"id": "https://turnstyle.io/schema/links.json",
"type": "object",
"additionalProperties": {
"oneOf": [
{
"type": "object",
"required": "href"
},
{
"type": "array",
"items": {
"type": "object",
"required": "href"
}
}
]
}
}
Passing example:
{
"customer": { "href": "/customer/1" },
"products": [
{ "href": "/product/1" },
{ "href": "/product/2" }
]
}
Failing example:
{
"customer": { "wrongKey": "/customer/1" },
"products": "aString"
}
Is it possible, and if so what is the proper syntax?
My assumption is that this will not work because the passing schema(s) in oneOf|anyOf|allOf of additionalProperties must apply to ALL keys falling under additionalProperties.
"required" should be an array of the properties which are mandatory in v4.
Or "required": true (or false) as part of the property in v3.
Try this:
{
"$schema": "http://json-schema.org/schema#",
"id": "https://turnstyle.io/schema/links.json",
"type": "object",
"additionalProperties": {
"oneOf": [
{
"type": "object",
"properties": {
"href": {"type": "string"}
},
"required": ["href"]
},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"href": {"type": "string"}
},
"required": ["href"]
}
}
]
}
}

json schema for dynamic array

I have the following json
{
"Dettype": "QTY",
"Details": [
{
"12568": {
"Id": 12568,
"qty":1,
"Freq":"2",
"Option": 0,
"promote":"yes"
},
"22456": {
"Id": 22456,
"qty":2,
"Freq":"3",
"Option": 1,
"promote":"no"
}
}
]
}
For the above json i need to write a json schema file which will valdiates the request.
but the problem is in array the key value for each item changes dynamically. If it is some constant value i can write but don't how to do the dynamic pattern
JSON schema i got
{
"type": "object",
"additionalProperties": true,
"properties": {
"Dettype": {
"type": "string"
},
"Details": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"properties": {
"**DYNAMIC VALUE**": {
"type": "object",
"additionalProperties": true,
"properties": {
"Id": {
"type": "integer"
},
"qty": {
"type": "integer"
},
"Freq": {
"type": "string"
},
"Option": {
"type": "integer"
},
"promote": {
"type": "string"
}
}
}
}
}
}
}
}
Can some one tell what changes need to be done for schema
This is what patternProperties is for.
Here it seems your object member keys are always digits; therefore you can write things like this:
"type": "object",
"patternProperties": {
"^\\d+$": {
"type": "object",
"etc": "etc"
}
}
You can also use additionalProperties if you want all properties to match some schema:
{
"type": "object",
"additionalProperties": {
"type": "object",
"etc": "etc"
}
}

How to use definitions in JSON schema (draft-04)

The rest service response I am working with is similar to following example, I have only included 3 fields here but there are many more:
{
"results": [
{
"type": "Person",
"name": "Mr Bean",
"dateOfBirth": "14 Dec 1981"
},
{
"type": "Company",
"name": "Pi",
"tradingName": "Pi Engineering Limited"
}
]
}
I want to write a JSON schema file for above (draft-04) which will explicitly specify that:
if type == Person then list of required properties is ["type", "name", "dateOfBirth", etc]
OR
if type == "Company" then list of required properties is ["type", "name", "tradingName", etc]
However am unable to find any documentation or example of how to do it.
Currently my JSON schema looks like following:
{
"$schema": "http://json-schema.org/draft-04/schema",
"type": "object",
"required": ["results" ],
"properties": {
"results": {
"type": "array",
"items": {
"type": "object",
"required": ["type", "name"],
"properties": {
"type": { "type": "string" },
"name": { "type": "string" },
"dateOfBirth": { "type": "string" },
"tradingName": { "type": "string" }
}
}
}
}
}
Any pointers/examples of how I should handle this.
I think the recommended approach is the one shown in Json-Schema web, Example2. You need to use an enum to select schemas "by value". In your case it would be something like:
{
"type": "object",
"required": [ "results" ],
"properties": {
"results": {
"type": "array",
"items": {
"oneOf": [
{ "$ref": "#/definitions/person" },
{ "$ref": "#/definitions/company" }
]
}
}
},
"definitions": {
"person": {
"properties": {
"type": { "enum": [ "person" ] },
"name": {"type": "string" },
"dateOfBirth": {"type":"string"}
},
"required": [ "type", "name", "dateOfBirth" ],
"additionalProperties": false
},
"company": {
"properties": {
"type": { "enum": [ "company" ] },
. . .
}
}
}
}
Sorry,
I don't get the point. The question is about the 'dependencies' keyword which is part of the last JSON Schema specification, right?
I do not find 'dependencies' in the accepted answer (?)
It is briefly explained in the last draft.
But http://usingjsonschema.com explained both property and definition dependencies in the book:
http://usingjsonschema.com/assets/UsingJsonSchema_20140814.pdf
start at page 29 (see, explained at page 30)
"dependencies": {
"shipTo":["shipAddress"],
"loyaltyId":["loyaltyBonus"]
}