Typed JSON is a format for defining structured JSON data, that can be used by language type systems or contract / guard librarires to do some type safety guarantees.
Every type is associtade with a unique URI. It is recommended to have a type definition under that URI, but it is not a requirement, it is up to implementor to associate actual definitions with a URI, in other words type URIs are just a unique identifiers for types.
Format defines some base primitive types that are also associated with specific URIs. This specification recognizes following primitive types:
Primitive type representing an absense of value. In the type vocabulary they can be referenced either by URI or aliased as a local type and referced by alias name:
{
"null": "http://typed-json.org/#Null"
}
Note: Above definition defines "null"
just as an alias to primitive
http://typed-json.org/#null type, so that rest of the type vocabulary
would be able to refer to it by that identifier.
Since null
is valid JSON primitive it can be used instead of URI
http://typed-json.org/#null. For example type empty
can be defined
as an alias to http://typed-json.org/#null as follows:
{
"empty": null
}
Boolean type can be aliased as bool
as follows:
{
"bool": "http://typed-json.org/#boolean"
}
Ints type can be aliased as int
as follows:
{
"int": "http://typed-json.org/#int"
}
Note: int is JS int
Float type can be aliased as float
as follows:
{
"float": "http://typed-json.org/#float"
}
String type can be aliased as float
as follows:
{
"string": "http://typed-json.org/#string"
}
Typed JSON is used mainly for defining composite type structures. There are few type structures that can be expressed:
Record types represent JSON objects with a specific structure. They are defined in terms of field type signatures:
{
"point": {
"x": "http://typed-json.org/#int",
"y": "http://typed-json.org/#int"
}
}
Above JSON defines point
type that Must have x
and y
fields
of int
type. This example uses full URIs to for field type definitions,
but that's redundant and could be expressed in more eloquent manner:
{
"int": "http://typed-json.org/#int",
"point": { "x": "int", "y": "int" }
}
Composite data type definitions can refer to other composite types:
{
"int": "http://typed-json.org/#int",
"point": { "x": "int", "y": "int" },
"line": {
"start": "point",
"end": "point"
}
}
Collections like arrays (different languages could use different collection types, lists for example) must contain items of certain type(s) and are defined as follows:
{
"int": "http://typed-json.org/#int",
"point": { "x": "int", "y": "int" },
"shape": ["point"]
}
Note: Above example above defines shape
type that is
collection of point
type items of arbitrary number
Following JSON data would match shape
type:
[{"x":0, "y":0}]
[{"x":0, "y":0}, {"x": 0, "y": 10}]
[{"x":0, "y":0}, {"x": 0, "y": 10}, {"x": 10: "y": 10}]
It is also possible to define fixed size collections:
{
"int": "http://typed-json.org/#int",
"point": ["int", 2],
"line": ["point", 2]
}
Following JSON data would match line
type definition:
[[0,0], [0,10]]
[[0,0], [10,10]]
Tuples are fixed size JS arrays, in contrast to regular fixed size arrays they define element types by index and there for are preferable for defining mixed type arrays:
{
"int": "http://typed-json.org/#int",
"string": "http://typed-json.org/#string",
"color": "string",
"point": { "x": "int", "y": "int" },
"pixel": {
"0": "point",
"1": "color"
}
}
Above defined pixel
type defines structure for values like:
[{x:0, y:0}, "red"]
[{x:0, y:12}, "green"]
Note: That "color" is just an alias for a string with a different semantic meaning. It's useful to give semantic meaning to an entities used in type definitions, that allows changing types of those entities independently from computed types
New primitives can be defined by aliasing existing primitive types
and adding some additional metadata. For example type digit
can
be defined as:
{
"digit": "http://typed-json.org/#int",
"digit:meta": {
"min": 0,
"max": 9
}
}
Note that above definition uses "digit:meta" key to define metadata
for the digit
type. Metadata keys must be mapped to an objects who's
fields are not specified by this format. Different environments may
choose to support metadata fields, for example digit
type metadata
specifies range of ints, but if runtime does not supports ranges it
will still treat digit
as int
type.
Specification recognizes constants of string
, integer
, float
and boolean
types:
{
"readyStatus": 1,
"readyState": "'complete'",
"yes": true,
}
Above data structure defines type readyStatus
constant of int
type that will only match 1
. Type yes
is a boolean that is
true
. Type readyState
is a constant primitive that matches
"complete"
string in JSON although in some languages that could
translate to more appropriate contant values like keywords
in clojure.
Composite types can also be defined in form of [union types][] to allow structures that can contain either of listed types:
{
"string": "http://typed-json.org/#string",
"pending": { "pending": true },
"complete": { "data": "string" },
"status": "pending|complete"
}
Unions can be defined over constant types as well:
{
"yes": "'yes'",
"no": "'no'",
"show": "yes|no"
}
There is also syntax sugar to express above in more consise way:
{
"show": "'yes'|'no'"
}
Note: Union types support syntax sugar over string type constants all others have to be defined as types explicitly
{
"two": 2,
"three": 3,
"five": 5,
"seven": 7,
"primedigits": "two|three|five|seven"
}