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.
Related
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.
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
]
}
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".
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)
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.