Should JSON-schema require documents to declare `$schema` (be self-referential)? - json

JSON-schema says that a JSON document can declare the schema to which the document conforms using the $schema property. Example:
{
"$schema": "http://example.com/example_fancy_schema#",
"example_fancy_property": "cute fluffy kittens"
}
where the schema looks like:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Example Fancy Schema",
"description": "The schema that describes the example format.",
"type": "object",
"properties": {
"example_fancy_property": {
"type": "string",
"enum": ["cute fluffy kittens"]
}
},
"additionalProperties": false,
"required": [ "example_fancy_property" ]
}
Does this mean that one should add a property for this in the actual schema, e.g.:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Example Fancy Schema",
"description": "The schema that describes the example format.",
"type": "object",
"properties": {
"$schema": {
"type": "string",
"enum": ["http://example.com/example_fancy_schema#"]
},
"example_fancy_property": {
"type": "string",
"enum": ["cute fluffy kittens"]
}
},
"additionalProperties": false,
"required": [ "$schema", "example_fancy_property" ]
}
None of the examples on the JSON-schema website appear to declare this, so I suspect one isn't supposed to declare it. But I'm curious anyway :)

The $schema keyword is recommended for use in JSON Schemas, to denote the version of the schema standard being used.
However, it has no special meaning in data. Over HTTP, there are recommended ways to associate data with a schema, but the $schema property is not one of them.

Related

Everit validator: JsonSchema property named "type"

Using Everit, I'm trying to come up with a json schema that validates
{
"type": "my content type",
"name": "content name"
}
My solution:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "model.json",
"type": "object",
"properties": {
"type": {
"type": "string",
"minLength": 1
},
"name": {
"type": "string",
"minLength": 1
}
},
"additionalProperties": false,
"required": [
"type",
"name"
]
}
This generates the error:
properties/type: expected type is one of JsonArray or String, found: JsonObject
This schema loads just fine:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "model.json",
"type": "object",
"properties": {
"some-type": { <<-- Only field name changed
"type": "string",
"minLength": 1
},
"name": {
"type": "string",
"minLength": 1
}
},
"additionalProperties": false,
"required": [
"some-type",
"name"
]
}
But the 'type' field is a database field that I don't want to rename.
How can I define the json schema to work with the property named 'type'?
Is the 'type' property name directly under properties interpreted as a reserved keyword?
Thx,
Ronald
According to another validator (https://www.jsonschemavalidator.net/) your schema is completely fine.
This might be a bug in the Everit validator, so you could consider looking into alternatives as well. Personally, I've liked networknt/json-schema-validator so far but haven't tested with your particular example.
That being said, according to the Everit documentation when it determines the applicable Draft version, it looks for this:
"$schema": "http://json-schema.org/draft-07/schema"
However in your example you use:
"$schema": "http://json-schema.org/draft-07/schema#"
Might be worth trying again without the trailing fragment (#).

Is it a good idea to include schema name in JSON document

We are developing a public service that ingests JSON messages to be stored in the database.
Now this service is probably the first of many, and I'm working on a way to structure the JSON Schemas. We have a lot of experience with XML Schema, but JSON Schema is a bit new to us.
One the the ideas is to include a Header section into each JSON Schema that contains the schema name, the major version and a unique message ID
Here's a simplified version of such a schema
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://www.example.com/json/01/sampleMessage",
"type": "object",
"title": "Sample Message for stackoverflow",
"description": "version 01.01",
"properties": {
"Header": {
"$ref": "#/definitions/Header"
},
"EanGsrn": {
"description": "Unique identifier of the Headpoint.",
"type": "string",
"pattern": "^[0-9]{18}$"
},
"Sector": {
"description": "Sector for which the Headpoint is valid.",
"type": "string",
"enum": [
"Electricity", "Gas"
]
}
},
"additionalProperties": false,
"required": [
"Header", "EanGsrn", "Sector"
],
"definitions": {
"Header": {
"id": "#Header",
"type": "object",
"description": "Standard header for all messages",
"properties": {
"Schema": {
"description": "$id of the schema of this message",
"type": "string",
"enum": ["http://www.example.com/json/01/sampleMessage"]
},
"Version": {
"description": "The specific version of the shema of this message",
"type": "string",
"pattern": "^01\\.[0-9]{2,3}$"
},
"MessageId": {
"description": "Unique identifier for the Message",
"type": "string",
"pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$"
}
},
"required": [
"Schema", "Version", "MessageId"
],
"additionalProperties": false
}
}
}
The advantages of this should be:
A message for the wrong schema or major version would be rejected immediately at the schema validation step.
The JSON itself contains information about it's schema and version, making life easier for the people needing to investigate issues etc... later on.
Questions
Is this usual, or are there other best practices in the JSON world to handle things like this?
Is this a good idea, of am I missing something obvious here?
There is no "best practice" for defining how a JSON instance identifies the schema it should conform to outside of an HTTP request.
The spec provides a header name to define the schema, but this only works if your JSON data is always served over HTTP.
Other systems similar to yours have included this information in the JSON data as a header like section, but there's no defined "best practice" or approach which the specification itself details.

Can a property of an allOf item contain a $ref to another allOf items definition?

Is "#/allOf/1/properties/body/properties/foo" a valid $ref?
As stated in this article which explains $ref usage, it looks like it should be.
However both AJV and https://www.jsonschemavalidator.net/ seem to disagree.
Trying with a plain JSON Pointer it definitely seems to be possible: https://repl.it/repls/WretchedSpiritedMammoth
This is the schema I'm testing with.
{
"$schema": "http://json-schema.org/draft-06/schema#",
"type": "object",
"allOf": [
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "http:/example.org/example.schema.json",
"type": "object",
"properties": {
"type": {
"type": "string"
},
"body": {
"type": "object"
}
},
"required": [
"type",
"body"
]
},
{
"properties": {
"body": {
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "http://example.org/foo.schema.json",
"type": "object",
"properties": {
"foo": {
"type": "number",
"minimum": 1
},
"bar": {
"$ref": "#/allOf/1/properties/body/properties/foo"
}
},
"required": [
"foo",
"bar"
]
}
}
}
]
}
EDIT: These are the errors im getting:
jsonschemavalidator.net
Error parsing schema
Message: Error when resolving schema reference '#/allOf/1/properties/body/properties/foo'.
Path 'allOf[1].properties.body.properties.bar', line .., position ..
AJV:
can't resolve reference #/allOf/1/properties/body/properties/foo from id http://example.org/foo.schema.json"
Your schema is mostly right, although you've set an $id in a subschema.
The "$id" keyword defines a URI for the schema, and the base URI that
other URI references within the schema are resolved against.
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-00#section-9.2
By adding an $id to a subschema, you've reset the base URI for other URI references, which includes any use of $ref within the subschema and its children.
$ref
...Resolved against the current URI base, it identifies the URI of a
schema to use.
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-00#section-8
By changing your definition of bar to the following, your schema will be valid.
"bar": {
"$ref": "#/properties/foo"
}
Further edit as Relequestual requested in his later comment:
It is valid to have an absolute URI as subschema $id, but as noted it resets the base URI. The restrictions on $id values only apply when using it to create local URI fragment identifiers (if this does not mean anything to you, do not worry about it).
Referencing a property schema from another property schema directly is valid, but the more common best practice is to put such a schema under the "definitions" keyword and have both properties refer to that location. This is what I would recommend for maximum clarity:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"type": "object",
"allOf": [
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "http:/example.org/example.schema.json",
"type": "object",
"properties": {
"type": {
"type": "string"
},
"body": {
"type": "object"
}
},
"required": [
"type",
"body"
]
},
{
"properties": {
"body": {
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "http://example.org/foo.schema.json",
"type": "object",
"properties": {
"foo": {
"$ref": "#/definitions/whateverYouWantToCallIt"
},
"bar": {
"$ref": "#/definitions/whateverYouWantToCallIt"
}
},
"required": [
"foo",
"bar"
]
}
},
"definitions": {
"whateverYouWantToCallIt": {
"type": "number",
"minimum": 1
}
}
}
]
}

Required fields for properties within an array of objects schema definition

I have following schema definition. library is required. there can be many. so in that library object there are some other properties which is required. But though i use following code it is not validating. I mean book title is not required. title of the author is required.How can i fix this?
schema definition
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": ["library"],
"properties": {
"library": {
"type": "array",
"items": [
{"required":["title"],
"type": "object",
"properties": {
"title": {
"type": "string"
},
"author": {
"type": "string"
}
}
}
]
}}}
json input
{"library":[]
}
expected json input
{"library":[{"title":"Max"}]
}
I assume you want "json input" to fail.
If so, your problem is that you didn't describe a library with a book with missing title, Instead, your document says 'I am a library with no books'.
Failing JSON:
{"library":[{}]}
Alternately, if you want to probibit empty libraries: JSON Schema has a minLength property.
Your question is a little difficult to understand, but I noticed that you are using the tuple form of the items keyword. I'm sure that is not what you want. Try the following schema and I think it will behave the way you expect.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": ["library"],
"properties": {
"library": {
"type": "array",
"items": {
"required": ["title"],
"type": "object",
"properties": {
"title": {
"type": "string"
},
"author": {
"type": "string"
}
}
}
}
}
}

What is the purpose of the "description" field in JSON Schemas?

I'm not sure what the purpose of a JSON Schema "description" field is. Does the field serve as a space to comment? Does the field serve as an ID?
{
"id": "http://www.noodle.org/entry-schema#",
"schema": "http://json-schema.org/draft-04/schema#",
"description": "schema for online courses",
"type": "object",
"properties": {
"institution": {
"type": "object",
"$ref" : "#/definitions/institution"
},
"person": {
"type": "object",
"items": {
"type": "object",
"$ref": "#/definitions/person"
}
"definitions": {
"institution": {
"description": "University",
"type": "object",
"properties": {
"name":{"type":"string"},
"url":{
"format": "uri",
"type": "string"
},
"descriptionofinstitution":{"type":"string"},
"location": {
"description": "location",
"type": "string",
"required": true
}
}
}
According to the JSON-Schema specification (http://json-schema.org/latest/json-schema-validation.html#anchor98), the purpose of the "description" (and "title") fields is to decorate a user interface with information about the data produced by this user interface. A title will preferrably be short, whereas a description will provide explanation about the purpose of the instance described by this schema.
It is probably some additional explanation, in order to enhance the knowledge concerning the specific entry, if the id is not enough. Of course it doesn't affect the behavior of the code as code itself