Extend $ref object properties - jsonschema

I am using JSON schema to build a form and I have an object in "definitions" which I am referencing using $ref in two different places on the schema. At one of the instances I need to have one more property added to the referenced object, how can I achieve this?
{
"definitions": {
"settingsProperties": {
"$id": "#/definitions/settingsProperties",
"type": "object",
"properties": {
"thickness": {
"$id": "#/properties/defaultLayerSettings/thickness",
"type": "number",
"title": "Thickness:",
}
}
}
},
"properties": {
"layerSettings": {
"$id": "#/properties/layerSettings",
"type": "array",
"title": "Dynamic Layer Settings:",
"items": {
"title": "Dynamic Settings",
"type": "object",
"$ref": "#/definitions/settingsProperties", PLUS startLayer PROPERTY!!!!!!!!!!!!!!
"required": [
"startLayer"
]
}
}
}

Just add "properties": { "startLayer": { ... } } underneath the required keyword.
Note that if you are using any specification version earlier than draft 2019-09 (the current latest version), you will have to nest the $ref keyword inside an allOf. Additionally, the use of fragments (strings that include #) are not permitted in the $id keyword, although some outdated tools are generating schemas with this structure.

Related

Allow additional properties in reference schemas, but none else

Suppose I have two schema being used to validate a json file.
testSchema.json
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"additionalProperties": false,
"properties": {
"$schema": { "type": "string" },
"sample": { "type": "number" }
},
"anyOf": [
{ "$ref": "./testSchema2.json" },
{}
]
}
testSchema2.json
{
"$schema": "http://json-schema.org/draft-04/schema",
"type": "object",
"properties": {
"test": { "type": "string" },
"test2": { "type": "number" }
}
}
test.json
{
"$schema": "../testSchema.json",
"sample": 0,
"test": "some text" //this line throws error "Property is not allowed"
}
I'd like for the file to be validated against the included schema's properties and any schema that is referenced's properties. Am I missing something?
Edit: I want to exclude any objects that are not explicitly defined in any of my included/referenced schema.
From JSON Schema draft 2019-09 (after draft-07), this is possible by using the unevaluatedProperties keyword.
additionalProperties cannot "see through" applicator keywords such as "anyOf" and "$ref", and only works based on the properties in the same schema object.
This is not possible with draft-07 or previous.

What does "$ref": "#" mean?

Here is sample JSON schema code:
What is "$ref": "#" referring to?
Is it here? or do they mean the whole document?
You can find this entire schema on https://www.jsonschemavalidator.net
Select Schema Draft V7.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#" }
},
"nonNegativeInteger": {
"type": "integer",
"minimum": 0
},
"nonNegativeIntegerDefault0": {
"allOf": [
{ "$ref": "#/definitions/nonNegativeInteger" },
{ "default": 0 }
]
},....
I'm not expert, but I had same question and I think I found answer
... each $ref is resolved into a full URI. Once that is done, all your questions are answered by asking the question: What schema would I end up with, if I simply fetched that URI? Where the $ref is, how it was loaded, all of that is irrelevant - it's entirely dependent on the resolved URI.
The library might take some shortcuts (like caching documents so they are only fetched once, or trusting one schema to "speak for" another), but those are all implementation details.
# is not special: all values of $ref are resolved as URIs relative to the current document (or the closest value of "id", if there is one).
Therefore, if you haven't used "id", then # will point to the root of the schema document. If you fetched your schema from http://example.com/schema, then a {"$ref": "#"} anywhere inside that will resolve to http://example.com/schema#, which is the document itself.
Link: https://stackoverflow.com/a/17723151/989369
So basically it points to main scheme, i.e.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#" }
}
will convert to:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
...
}
}

Valid name for definitions item

Is it correct to make a definition (suppose with name "abc") and then refer to it from an attribute called "abc" whose type is "array"? Or it's incorrect and array and its items have to have different names?
Thanks!
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "newSchema.json",
"title": "newSchema",
"type": "object",
"definitions": {
"abc": {
"properties": {
"some_col": {
"description": "hi",
"type": "integer"
}
}
}
},
"properties": {
"abc": {
"type": "array",
"items": {
"$ref": "#/definitions/abc"
}
}
}
}
It's a totally valid JSON structure and JSON Schema setup.
If you intend for others to read your generated schemas, you could add annotations to them to give additional information, such as "This is an array of [table]" and "this object represents a row in [table]".
See the Schema Annotations section of the JSON Schema draft-7 validation specification.

How to use definitions from external files in JSON Schema?

I'm trying to import the definitions from another json schema using $ref but getting the following error:
can't resolve reference ../base/definitions.schema.json#/definitions/datetime from id #
{
"$schema": "http://json-schema.org/draft-06/schema#",
"definitions": {
"datetime": {
"type": "string"
},
"name": {
"type": "string"
},
}
}
{
"$schema": "http://json-schema.org/draft-06/schema#",
"properties": {
"active": {"type": "boolean"},
"created_at": { "$ref": "../base/definitions.schema.json#/definitions/datetime" },
"name": { "$ref": "../base/base/definitions.schema.json#/definitions/name" },
"updated_at": { "$ref": "../base/definitions.schema.json#/definitions/datetime" }
},
"required": ["name"],
"type": "object"
}
Directory structure:
api
-- base
-- definitions.schema.json
-- country
-- country.schema.json
I have tried several combinations by using an absolute path, a file url and several other combinations of the path. Not sure what's going on.
Schema validator: ajv#5.1.1
You need to add schemas using "addSchema" method. $ref is resolved relative to "id" attribute ("$id" in draft-06), ajv doesn't (and can't) use file paths.
EDIT: added $ref section to docs.

Is it possible to inline JSON schemas into a JSON document? [duplicate]

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.