json schema usage of definitions keyword - json

Can anyone please help me with usage of definitions in json schema. I had gone through their website and didn't get much information.
Any helps would be worth.

the definitions keyword is a standardized placeholder in which you can define inline subschemas to be used in a schema.
In other words, the definitions keyword defines subschemas that you can refer to elsewhere in the schema. Perhaps this is an easier example:
"properties": {
"cars": {
"type": "object",
"oneOf": [
{ "$ref": "#/definitions/ford" },
{ "$ref": "#/definitions/bmw" },
{ "$ref": "#/definitions/audi" }
]
}
},
"definitions": {
"ford": {
"origin": "USA"
},
"bmw": {
"origin": "Germany"
},
"audi": {
"origin": "Germany"
}
}
Under definitions you define subschemas, for example for ford that you can refer to elsewhere with "$ref": "#definitions/ford".

Related

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.

Metaschema specifying required attribute for all properties

I want to customize a metaschema such that all properties are required to have an additional attribute, for example, how could I require that all properties specify a "type"?
Then this schema should fail:
{
"$schema": "http://json-schema.org/schema#",
"title": "...",
"description": "...",
"type": "object",
"properties": {
"name": {
"description": "..."
}
}
}
But this one should succeed:
{
"$schema": "http://json-schema.org/schema#",
"title": "...",
"description": "...",
"type": "object",
"properties": {
"name": {
"description": "...",
"type": "string"
}
}
}
Unfortunately, writing meta-schemas is not easy. It's being worked on, but there's no good solution yet.
You would have to make a copy of the meta-schema you want to extend and then add "required": ["type"].
But, while we're here, maybe I can convince you not to do this. Making the type keyword required causes problems in some cases. Here are a few examples. https://github.com/json-schema/json-schema/issues/172#issuecomment-124214534
EDIT
After discussing this further, we found that this particular case doesn't have the problems we normally run into with extending meta-schemas because it doesn't need to be recursive. Here is an example of extending the draft-06 schema to include a new keyword called custom which is a boolean and is required only at the top level of a properties schema.
{
"allOf": [
{ "$ref": "http://json-schema.org/draft-06/schema#" },
{
"properties": {
"properties": {
"patternProperties": {
".*": {
"properties": {
"custom": { "type": "boolean" }
},
"required": ["custom"]
}
}
}
}
}
]
}
And here's an example schema that conforms to this meta-schema.
{
"properties": {
"foo": {
"custom": true,
"not": { "type": "string" }
}
}
}
The custom keyword is required for the "foo" schema, but not the not schema or the top level schema.

How to use Switch in JSON Schema 6 with multiple IFs

I have entity which is of array. I want to call different entity types based on a property called dataStoreType. My Schema looks like this:
"entities":{
"type":"array",
"switch":[
{
"if": {"properties":{"dataStoreType":"RELATIONAL"}},
"then":{"$ref": "#/definitions/entities-relational"}
},
{
"if": {"properties":{"dataStoreType":"DOCUMENT"}},
"then":{"$ref": "#/definitions/entities-no-sql"}
},
{
"if": {"properties":{"dataStoreType":"KEYVALUE"}},
"then":{"$ref": "#/definitions/entities-key-value"}
}
]
}
My instance JSON looks like this:
{
"name": "document-simple",
"dataStoreType": "RELATIONAL",
"entities": [
{
"name": "Employee",
"attributes": [
{
"name": "firstName",
"type": "STRING",
"required": true
},
{
"name": "lastName",
"type": "STRING"
},
}
]
}
But my Schema is not validating this instance correctly because I think there is some error in the switch. I am sure that JSON is not being validated because I have defined other rules for entities(which I have not mentioned) and when my instance violates that, the schema is not showing error.
What could be the error in my switch
Your main problem is that where you have:
"properties": {"dataStoreType": "RELATIONAL"}
what you actually need is:
"properties": {"dataStoreType": {"const": "RELATIONAL"}}
Beyond that, note that switch is no longer a JSON Schema proposal, but if/then/else has been accepted for the next draft (draft-07). So when using Ajv or another validator with early if support turned on, or moving to draft-07 when it is out and supported, you want:
"entities":{
"type":"array",
"oneOf": [
{
"if": {"properties":{"dataStoreType":{"const":"RELATIONAL"}}},
"then":{"$ref": "#/definitions/entities-relational"}
},
{
"if": {"properties":{"dataStoreType":{"const":"DOCUMENT"}}},
"then":{"$ref": "#/definitions/entities-no-sql"}
},
{
"if": {"properties":{"dataStoreType":{"const":"KEYVALUE"}}},
"then":{"$ref": "#/definitions/entities-key-value"}
}
]
}
This is the equivalent of a switch (without fall-through) or a chained set of else-ifs (which also works, but gets harder to read the more you chain).
Your if conditions are mutually exclusive, so oneOf is appropriate here and will do what you want.
I would definitely avoid using switch, as it has been pretty thoroughly rejected as a proposal for the standard. It is unlikely to ever be added.
JSON Schema Draft 6 does not support the "if" and "then" keywords. It is currently a proposal. Probably you use an implementation which already supports it (ajv, maybe?).
On the other hand you can achieve what you want using "oneOf" and "const" in the following way:
{
"oneOf" : [
{
"type": "object",
"properties": {
"dataStoreType": {
"const": "RELATIONAL"
},
"entities": {
"type": "array",
"items": {
"$ref": "#/definitions/entities-relational"
}
}
}
},
{
"type": "object",
"properties": {
"dataStoreType": {
"const": "DOCUMENT"
},
"entities": {
"type": "array",
"items": {
"$ref": "#/definitions/entities-no-sql"
}
}
}
},
// and here comes the KEYVALUE schema.. I think you get it now
]
}

Json-schema doesn't validate json with $ref-references

I have this json:
{
"categories": [
{
"id": 1,
"name": "cat1",
"topics": [
{
"$ref": "#/topics/1"
}
]
}
],
"topics": [
{
"id": 1,
"name": "top1"
}
]
}
And I've written the next schema to validate it:
{
"definitions": {
"category": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"topics": {
"type": "array"
"items": { "$ref": "#/definitions/topic" }
}
}
},
"topic": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
},
"type": "object",
"properties": {
"categories": {
"items": { "$ref": "#/definitions/category" },
"type": "array"
},
"topics": {
"items": { "$ref": "#/definitions/topic" },
"type": "array"
}
}
}
When I use this schema on popular online validators, it doesn't catch invalid references like #/topics/5 or #/ttt/555.
Can I use this schema to validate references? Can you suggest me library or service, that can do it?
Currently this is outside the scope of JSON Schema. The proposal #erosb mentions is still under consideration, but not for the soon-to-be-forthcoming draft-07. With enough demand it may be considered for draft-08. It would be a significant expansion of the project's scope, which is why it has been on hold while other things are addressed.
Some validators make it easy to define your own extension keywords, which may be a good way to do what you want. There are definitely libraries that will apply a JSON Pointer and let you find out if it points to anything or not. If you implement #erosb's proposal somewhere, it would be great if you could comment on the issue and let us know how it works out.
I'm not sure if I properly understand what you try to achieve. I assume you want to denote that the items of the "topics" array should be JSON references ("$ref" with a JSON Pointer) _and the pointed object should match the schema "#/definitions/topic".
If this is the case, then currently there is no way to express it with json schema, so - even with the latest version - you can only denote that a string should be a json pointer, but you can't make restrictions on what the type of the referenced object should be.
Last year I made a suggestion addressing this problem, but due to mixed feedback it got somewhat stuck.

How to tell JSON schema validator to pick schema from property value?

For example a schema for a file system, directory contains a list of files. The schema consists of the specification of file, next a sub type "image" and another one "text".
At the bottom there is the main directory schema. Directory has a property content which is an array of items that should be sub types of file.
Basically what I am looking for is a way to tell the validator to look up the value of a "$ref" from a property in the json object being validated.
Example json:
{
"name":"A directory",
"content":[
{
"fileType":"http://x.y.z/fs-schema.json#definitions/image",
"name":"an-image.png",
"width":1024,
"height":800
}
{
"fileType":"http://x.y.z/fs-schema.json#definitions/text",
"name":"readme.txt",
"lineCount":101
}
{
"fileType":"http://x.y.z/extended-fs-schema-video.json",
"name":"demo.mp4",
"hd":true
}
]
}
The "pseudo" Schema note that "image" and "text" definitions are included in the same schema but they might be defined elsewhere
{
"id": "http://x.y.z/fs-schema.json",
"definitions": {
"file": {
"type": "object",
"properties": {
"name": { "type": "string" },
"fileType": {
"type": "string",
"format": "uri"
}
}
},
"image": {
"allOf": [
{ "$ref": "#definitions/file" },
{
"properties": {
"width": { "type": "integer" },
"height": { "type": "integer"}
}
}
]
},
"text": {
"allOf": [
{ "$ref": "#definitions/file" },
{ "properties": { "lineCount": { "type": "integer"}}}
]
}
},
"type": "object",
"properties": {
"name": { "type": "string"},
"content": {
"type": "array",
"items": {
"allOf": [
{ "$ref": "#definitions/file" },
{ *"$refFromProperty"*: "fileType" } // the magic thing
]
}
}
}
}
The validation parts of JSON Schema alone cannot do this - it represents a fixed structure. What you want requires resolving/referencing schemas at validation-time.
However, you can express this using JSON Hyper-Schema, and a rel="describedby" link:
{
"title": "Directory entry",
"type": "object",
"properties": {
"fileType": {"type": "string", "format": "uri"}
},
"links": [{
"rel": "describedby",
"href": "{+fileType}"
}]
}
So here, it takes the value from "fileType" and uses it to calculate a link with relation "describedby" - which means "the schema at this location also describes the current data".
The problem is that most validators do not take any notice of any links (including "describedby" ones). You need to find a "hyper-validator" that does.
UPDATE: the tv4 library has added this as a feature
I think cloudfeet answer is a valid solution. You could also use the same approach described here.
You would have a file object type which could be "anyOf" all the subtypes you want to define. You would use an enum in order to be able to reference and validate against each of the subtypes.
If the sub-types schemas are in the same Json-Schema file you don't need to reference the uri explicitly with the "$ref". A correct draft4 validator will find the enum value and will try to validate against that "subschema" in the Json-Schema tree.
In draft5 (in progress) a "switch" statement has been proposed, which will allow to express alternatives in a more explicit way.