Encapsulate Root object by name in Json schema for reuse? - json

I'm trying to create a Json schema for an object. Is it possible to reference the top level root object, when defining an embedded object within it?
I've seen that I can reuse a definition through $ref:"#/definitions/..." but I am trying to reuse the whole top level object. Not just the properties within.
if my json looks like this:
{
"name": "brodie",
"age": 2,
"bestFriend": {
"name": "clara",
"age": 4,
"bestFriend": {
"name": "stella",
"age" : 5
}
}
}
I can create a json schema that looks like this:
{
"type": "object",
"properties": {
"name": {
"$ref": "#/definitions/name"
},
"age": {
"$ref": "#/definitions/age"
},
"bestFriend": {
"$ref": "#/definitions/bestFriend"
},
},
"definitions": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"bestFriend": {
"type": "object",
"allOf": [
{"$ref": "#/defintions/name"},
{"$ref": "#/definitions/age"},
{"$ref": "#/definitions/bestFriend"}
]
}
}
}
But I'd like to do something like
{
"type": "object",
"title": "bestFriend",
"properties": {
"$ref": "#/definitions/bestFriend"
},
"definitions": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"bestFriend": {
"type": "object",
"allOf": [
{"$ref": "#/defintions/name"},
{"$ref": "#/definitions/age"},
{"$ref": "#/definitions/bestFriend"}
]
}
}
}
I am using the same json object for all 3 instances brodie, clara, stella. I want to encapsulate the top level object as one definition so I can reference it later in a cleaner way. It would be nice if I didn't have the list of $refs at the top and only had them within the "definitions" object at the bottom. Is this even possible? Or is what I have above the recommended pattern.
(I know I could define some of these fields inline, but I plan on heavily reusing some json objects, and felt it would be cleaner if everything was defined in the "definitions" section.)

Related

JSON Schema reference resolution

I have a JSON schema that contains "$ref" tags and I am trying to get a version of the JSON schema that have the "$ref" tags resolved. I am only looking to resolve "$ref" from definition (tags) within the JSON Schema string (ie. not external resolution needed).
Is there a library that performs the resolution of the JSON Schema? (I am currently using org.everit.json.schema library, which is great, but I can't find how to do what I need).
For example, my original schema is:
{
"$id": "https://example.com/arrays.schema.json",
"description": "A representation of a person, company, organization, or place",
"title": "complex-schema",
"type": "object",
"properties": {
"fruits": {
"type": "array",
"items": {
"type": "string"
}
},
"vegetables": {
"type": "array",
"items": { "$ref": "#/$defs/veggie" }
}
},
"$defs": {
"veggie": {
"type": "object",
"required": [ "veggieName", "veggieLike" ],
"properties": {
"veggieName": {
"type": "string",
"description": "The name of the vegetable."
},
"veggieLike": {
"type": "boolean",
"description": "Do I like this vegetable?"
}
}
}
}
}
Which would resolve to something like this (notice that the "#defs/veggie" resolves to its definition inserted inline in the schema):
{
"$id": "https://example.com/arrays.schema.json",
"description": "A representation of a person, company, organization, or place",
"title": "complex-schema",
"type": "object",
"properties": {
"fruits": {
"type": "array",
"items": {
"type": "string"
}
},
"vegetables": {
"type": "array",
"items": {
"type": "object",
"required": [ "veggieName", "veggieLike" ],
"properties": {
"veggieName": {
"type": "string",
"description": "The name of the vegetable."
},
"veggieLike": {
"type": "boolean",
"description": "Do I like this vegetable?"
}
}
}
}
}
}
This isn't possible in the general sense, because:
the $ref might be recursive (i.e. reference itself again)
the keywords in the $ref might duplicate some of the keywords in the containing schema, which would cause some logic to be overwritten.
Why do you need to alter the schema in this way? Generally, a JSON Schema implementation will resolve the $refs automatically while evaluating the schema against provided data.

Json Schema different input formats

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

Json schema to validate object's values against content of another object

I'm trying to create json schema for a document where field values in some object should validate against a enum defined in another object in the same document.
More specifically, in the example below, I'd like to be able to define "properties" with id and values (I should be able to define different properties in different json files).
Then "objects" should be able to refer to these properties, so that object.properties[i].id must match with id of one of the properties and object.properties[i].value must match with one of the enum values defined for that property.
{
"properties": [
{
"id": "SIZE",
"values": ["small", "medium", "big"]
},
{
"id": "MATERIAL",
"values": ["wood", "glass", "steel", "plastic"]
},
{
"id": "COLOR",
"values": ["red", "green", "blue"]
}
],
"objects": [
{
"name": "chair",
"properties": [
{
"id": "SIZE",
"value": "small"
},
{
"id": "COLOR",
"value": "red"
}
],
},
{
"name": "table",
"properties": [
{
"id": "MATERIAL",
"value": "wood"
}
]
}
]
}
I tried to create json schema to validate such structure, but got stuck with describing reference to inner fields of "property" object. I also looked into the standard and did not find a way to achieve the goal.
Is it possible to create a json schema which would validate my json files?
There is a proposal for $data reference that almost allows to do it if you change your data structure a little bit to remove one level of indirection. It's is supported in Ajv (I am the author).
So if your data were:
{
"properties": {
"SIZE": ["small", "medium", "big"],
"MATERIAL": ["wood", "glass", "steel", "plastic"],
"COLOR": ["red", "green", "blue"]
},
"objects": {
"chair": {
"SIZE": "small",
"COLOR": "red"
},
"table": {
"MATERIAL": "wood"
}
}
}
then your schema could have been:
{
"type": "object",
"properties": {
"properties": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": { "type": "string" }
}
},
"objects": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"SIZE": {"enum": {"$data": "3/properties/SIZE"}},
"MATERIAL": {"enum": {"$data": "3/properties/MATERIAL"}},
"COLOR": {"enum": {"$data": "3/properties/MATERIAL"}}
}
}
}
}
}
And it could be dynamically generated based on all list of possible properties.
With the data structure you have you either can use custom keywords if the validator supports them or implement some part of validation logic outside of JSON schema.

How to describe this validation requirement in jsonschema?

I want to validate my API json response like this:
{
"code": 0,
"results": [
{"type":1, "abc": 123},
{"type":2, "def": 456}
]
}
I want to validate the objects within results to have a "abc" field when its type is 1, and "def" field when its type is 2. The results may contain arbitrary number of type1 and type2 objects.
Can I specify this in jsonschema? Or must I use a generic validator for elements in results and do validation myself?
You can do this using the anyOf keyword.
An instance validates successfully against this keyword if it validates successfully against at least one schema defined by this keyword's value.
http://json-schema.org/latest/json-schema-validation.html#anchor85
You need to define both types of items and then use anyOf To describe the array items for "results".
{
"type": "object",
"properties": {
"code": { "type": "integer" },
"results": {
"type": "array",
"items": { "$ref": "#/definitions/resultItems" }
}
},
"definitions": {
"resultItems": {
"type": "object",
"anyOf": [
{ "$ref": "#/definitions/type1" },
{ "$ref": "#/definitions/type2" }
]
},
"type1": {
"properties": {
"type": { "enum": [1] },
"abc": { "type": "integer" }
},
"required": ["abc"]
},
"type2": {
"properties": {
"type": { "enum": [2] },
"def": { "type": "integer" }
},
"required": ["def"]
}
}
}

A common JSON Schema for similar structure

I'm completely new to json and json schema, so I have a question (yet I don't know how much it make sense). Can we create a json schema which is common for similar type of structure. For example:
One single schema can be used to validate following json
JSON:
{
"Team_Table":
[{"Name":"New Zealand", "Match":"Six", "Won":"Six"}]
}
And
{
"Story_Taller":
[{"Story":"No Name", "Chapter":"Don't know"}]
}
Similarities:
Both have only one object in the array
Objects have string value.
Dissimilarities:
Number of properties are different
Keys are different in both
Can we do this?
Maybe this helps you along:
{
"properties": {
"Story_Taller": {
"type": "array",
"maxItems": 1,
"items": {
"properties": {
"Chapter": {
"type": "string"
},
"Story": {
"type": "string"
}
},
"additionalProperties": false
}
},
"Team_Table": {
"type": "array",
"maxItems": 1,
"items": {
"properties": {
"Name": {
"type": "string"
},
"Match": {
"type": "string"
},
"Won": {
"type": "string"
}
},
"additionalProperties": false
}
}
},
"oneOf": [
{
"title": "Story_Taller",
"required": [
"Story_Taller"
]
},
{
"title": "Team_Table",
"required": [
"Team_Table"
]
}
]
}
in (short) words:
in your JSON there must be one property of either "Story_Taller" or "Team_Table" with a maximum of 1 item
"oneOf": [ ... ]
Properties of both arrays are defined by items
"Story_Taller" must have "Chapter" and "Story" and no additional properties.
"Team_Table" must have "Name", "Match", "Won" and no additional properties.
And all of them are defined as strings.