JSON X-Type is a data type format for describing JSON-like structures in a simple and natural way. Any valid JSON could be validated against a JSON X-Type definition.
Keyword | Description | Usage |
---|---|---|
string | String type. | key, value |
number | Number type. | value |
boolean | Boolean type. | value |
null |
The null value. The string "null" value doesn't have a special meaning. |
value |
undefined | Value is not set (the corresponding key is not present). | value |
array | Array generic. | key |
any | Any value (not validated). | value |
$and | Refers to the intersection of an array members (🔗). | key |
$descriptions | Object with descriptions of the fields at the same level. | key |
$ref | Reference to another JSON X-Type (🔗). | key |
$schema | A literal JSON Schema definition (🔗). | key |
The list could be extended with other $
-prefixed keywords.
So it's a good idea to escape any values that start with $
using the $literal
prefix.
Prefixes are used to modify what's going after them. Prefixes and the actual values are separated by a colon.
Prefix | Description | Usage |
---|---|---|
$literal | Escapes a literal value (🔗). | key, value |
Object literals describe object-like schemas:
{
"name": "string",
"age": "number"
}
The example above defines an object with only two properties, both of which are required.
Also, it is possible to use the string
type as a key to describe records:
{
"string": "any"
}
Array literals allow defining multiple available options, one of which is applicable:
["string", "undefined"]
It is possible to combine several types into one using the $and
keyword:
{
"$and": [{"foo": "string"}, {"bar": "number"}]
}
A result is an object that contains all of the properties of all the items:
{
"foo": "string",
"bar": "number"
}
A TypeScript analogy of the $and
operator is the following:
type And<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never
type Combined = And<{foo: string} | {bar: number}> // {"foo": "string"} & {"bar": "number"} ≡ {"foo": "string", "bar": "number"}
Effectively, it applies the AND
relation between the array members, replacing the XOR
relation.
Note that it doesn't make sense to combine primitive types or objects that have common properties with different types:
{
"$and": [{"foo": "string"}, {"foo": "number"}]
}
The example above results in foo
being both string
and number
, effectively equivalent to TypeScript's never
type.
The $schema
properties also cannot be combined using the $and
notation.
Impossible combinations should result in the undefined
type.
Whenever there is a need to use a literal string value instead of a reserved keyword, it needs to be prepended with the $literal
prefix:
{
"$literal:string": "boolean"
}
This will check for an object with the string
key of a boolean
value, e.g.:
{
"string": true
}
It is possible to refer to other JSON X-Types using the JSON Pointer syntax:
{
"foo": {"$ref": "#/path/to/field"}
}
A reference must be resolved relative to the file it appears in.
The $ref
expression must be replaced with the value of the field it refers to.
Any other properties passed alongside the $ref
must be ignored.
Alternatively, the $ref
keyword could be used as a prefix which is easier to write and read (but the support is up to the implementation):
{
"foo": "$ref:#/path/to/field"
}
If a reference is not resolved, it should be treated as any
.
If there's something that cannot be expressed in terms of JSON X-Type, it should go under this key:
{
"$schema": {
"type": "string",
"contentMediaType": "application/jwt",
"contentSchema": {"type": "array"}
}
}
Possible extensions described here