Variables
$vars keyword
Variables provide a new way to tackle
different scenarios where JSON schema alone fails.
This means, that you can use a new keyword named $vars
to make your life easier.
$vars
can be used as:
- substitution variables for URI templates
- arguments to filters
General structure
In a JSON schema document, $vars
must be an object but
the values inside $vars
can be anything.
Example of $vars
:
{
"$vars": {
"some-number": 123,
"some-data": "data",
"my-array": [1, 2, null, "str"],
"the-object": {
"a": 10,
"b": 5
}
}
}
Data reference values
In the above example, $vars
contains only constant values,
making you wonder why it was named like so. The reason is simple,
because you can access the current data being validated using
JSON pointers.
To do this, you will reference a value in the same way you reference
other schemas: by using $ref
keyword.
If the $ref
cannot be resolved, an error is thrown.
You can prevent this by adding a fallback value
using the default
keyword next to the $ref
keyword.
Take a look at the next example:
{
"$vars": {
"value-of-prop-a": {"$ref": "/a"},
"secret-value": {
"$ref": "/deep/secret",
"default": "if /deep/secret points to nothing this is the fallback value"
},
"some-constant": 5
}
}
considering that we validate the following data
{
"a": "A",
"deep": {
"secret": "S"
},
"constant": 10
}
the $vars
will become
{
"value-of-prop-a": "A",
"secret-value": "S",
"some-constant": 5
}
As you can see, the $ref
contains an absolute JSON pointer, but
can also use relative JSON pointers.
Here is an example using a schema:
{
"$id": "http://example.com/vars-example-1#",
"type": "object",
"properties": {
"prop-a": {
"type": "string"
},
"prop-b": {
"$vars": {
"value-of-prop-a": {"$ref": "1/prop-a"},
"some-constant": 5
}
}
}
}
considering that data we validate is
{
"prop-a": "A",
"prop-b": "B"
}
then the $vars
will become
{
"value-of-prop-a": "A",
"some-constant": 5
}
You might have some questions right now, but here is a list of Q&A to get a better understanding of what’s happening.
- Why
1/prop-a
and not0/prop-a
?
Because 0
points to value "A"
,
which is a string and doesn’t have a prop-a
key to descend into, but 1
points to the object
that holds the property prop-a
, so it can descend.
- What about
2/prop-a
?
Well, in our example it is impossible to ascend 2 levels because at level 1 we are already at the root. So an error will be thrown.
- Where can I find more info about these pointers?
Go to the JSON Pointers page.
- Where is this useful?
See below.
Variables and URI templates
$vars
can act as substitutions/variables in URI templates. In other words,
you can dynamically reference schemas based on the current data being validated.
Please note that data can come from an untrusted source,
so it is better to filter it before by using enum
or other JSON Schema
keywords including $filters if needed. Also, use URI template
escaping mechanisms.
You can disable uri-templates by setting the allowTemplates
option to false
.
Here is an example that validates a number by using number’s type.
{
"$id": "http://example.com/number#",
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["natural", "integer", "real", "complex"]
},
"value": {
"$ref": "#/definitions/{+number-type}",
"$vars": {
"number-type": {"$ref": "1/type"}
}
}
},
"required": ["type", "value"],
"definitions": {
"natural": {
"type": "integer",
"minimum": 0
},
"integer": {
"type": "integer"
},
"real": {
"type": "number"
},
"complex": {
"type": "object",
"properties": {
"a": {
"type": "number"
},
"b": {
"type": "number"
}
},
"required": ["a", "b"],
"additionalProperties": false
}
}
}
First, we see that $ref
of value
property is an uri template, having the number-type
placeholder.
That placeholder will be replaced with the value of the variable having the same name from $vars
.
So, if $vars
is {"number-type": "test"}
the $ref
will become #/definitions/test
.
Second, the $ref
from number-type
property of $vars
denotes a relative
JSON pointer. Instead of using the object as placeholder, the value will be
resolved, in our case it will use the value of type
property from our data (not schema).
Consider the following data to be validated against our schema:
{"type": "natural", "value": 58}
the steps for validating the value
property are:
- get
$ref
=>#/definitions/{number-type}
- resolve
$vars
=>{"number-type": "natural"}
- replace placeholders in
$ref
=>#/definitions/natural
- resolve
#/definitions/natural
sub-schema =>{"type": "integer", "minimum": 0}
- validate
58
against resolved sub-schema => valid
Global variables
Depending on your project, sometimes you’ll want certain variables
to always be available when validating. Usually, global variables are set from PHP,
but you can override global variables before referencing another schema by
using the $globals
keyword.
You can disable $globals keyword by setting the allowGlobals
option to false
.
Global variables example
{
"type": "object",
"properties": {
"prop-a": {
"$ref": "http://example.com/vendor/{VENDOR_VERSION}/a.json"
},
"prop-b": {
"$ref": "http://example.com/vendor/{VENDOR_VERSION}/b.json",
"$vars": {
"VENDOR_VERSION": "2.0"
}
},
"prop-c": {
"$ref": "http://example.com/vendor/{VENDOR_VERSION}/c.json",
"$vars": {
"version": 5
}
},
"prop-d": {
"$ref": "http://example.com/vendor/{VENDOR_VERSION}/d.json",
"$globals": {
"VENDOR_VERSION": "3.0"
}
}
}
}
Considering that our global variables are:
{
"VENDOR_VERSION": "1.0"
}
the $ref
s will be
Property | Value | Reason |
---|---|---|
prop-a |
http://example.com/vendor/1.0/a.json |
global variable VENDOR_VERSION is 1.0 |
prop-b |
http://example.com/vendor/2.0/b.json |
local variable VENDOR_VERSION is 2.0 |
prop-c |
http://example.com/vendor/1.0/c.json |
global variable VENDOR_VERSION is 1.0 and there is no local variable VENDOR_VERSION |
prop-d |
http://example.com/vendor/1.0/d.json |
global variable VENDOR_VERSION is 1.0 and there is no local variable VENDOR_VERSION . However, inside the referenced schema the value of VENDOR_VERSION will be set to 3.0 |