Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ucarion/908bcea9feed1f298fc242784c05f643 to your computer and use it in GitHub Desktop.
Save ucarion/908bcea9feed1f298fc242784c05f643 to your computer and use it in GitHub Desktop.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc2629 version 1.2.13 -->
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
<!ENTITY RFC3339 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.3339.xml">
<!ENTITY RFC4287 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.4287.xml">
<!ENTITY RFC6901 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.6901.xml">
<!ENTITY RFC8259 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.8259.xml">
<!ENTITY RFC8610 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.8610.xml">
<!ENTITY RFC2119 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml">
<!ENTITY RFC8174 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml">
<!ENTITY RFC7071 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.7071.xml">
<!ENTITY RFC7493 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.7493.xml">
<!ENTITY I-D.handrews-json-schema SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml3/reference.I-D.handrews-json-schema.xml">
]>
<?rfc toc="yes"?>
<?rfc sortrefs="yes"?>
<?rfc symrefs="yes"?>
<rfc ipr="trust200902" docName="draft-ucarion-json-type-definition-04" category="exp">
<front>
<title>JSON Type Definition</title>
<author initials="U." surname="Carion" fullname="Ulysse Carion">
<organization abbrev="Segment">Segment.io, Inc</organization>
<address>
<postal>
<street>100 California Street</street>
<city>San Francisco</city>
<code>94111</code>
<country>United States of America</country>
</postal>
<email>ulysse@segment.com</email>
</address>
</author>
<date year="2020" month="June" day="28"/>
<area>Applications</area>
<workgroup>Independent Submission</workgroup>
<keyword>Internet-Draft</keyword>
<abstract>
<t>This document proposes a format, called JSON Type Definition (JTD), for
describing the shape of JavaScript Object Notation (JSON) messages. Its main
goals are to enable code generation from schemas as well as portable validation
with standardized error indicators. To this end, JTD is intentionally limited to
be no more expressive than the type systems of mainstream programming languages.
This intentional limitation, as well as the decision to make JTD schemas be JSON
documents, makes tooling atop of JTD easier to build.</t>
<t>This document does not have IETF consensus and is presented here to facilitate
experimentation with the concept of JTD.</t>
</abstract>
</front>
<middle>
<section anchor="introduction" title="Introduction">
<t>This document describes a schema language for JSON <xref target="RFC8259"/> called JSON Type
Definition (JTD).</t>
<t>There exist many options for describing JSON data. JTD’s niche is to focus on
enabling code generation from schemas; to this end, JTD’s expressiveness is
intentionally limited to be no more powerful than what can be expressed in the
type systems of mainstream programming languages.</t>
<t>The goals of JTD are to:</t>
<t><list style="symbols">
<t>Provide an unambiguous description of the overall structure of a JSON
document.</t>
<t>Be able to describe common JSON datatypes and structures. That is, the
datatypes and structures necessary to support most JSON documents, and which
are widely understood in an interoperable way by JSON implementations.</t>
<t>Provide a single format that is readable and editable by both humans and
machines, and which can be embedded within other JSON documents. This makes
JTD a convenient format for tooling to accept as input or produce as output.</t>
<t>Enable code generation from JTD schemas. JTD schemas are meant to be easy to
convert into data structures idiomatic to mainstream programming languages.</t>
<t>Provide a standardized format for error indicators when data does not conform
with a schema.</t>
</list></t>
<t>JTD is intentionally designed as a rather minimal schema language. Thus,
although JTD can describe some categories of JSON, it is not able to describe
its own structure: this document uses Concise Data Definition Language (CDDL)
<xref target="RFC8610"/> to describe JTD’s syntax. By keeping the expressiveness of the
schema language minimal, JTD makes code generation and standardized error
indicators easier to implement.</t>
<t>Examples in this document use constructs from the C++ programming language.
These examples are provided to aid the reader in understanding the principles of
JTD, but are not limiting in any way.</t>
<t>JTD’s feature set is designed to represent common patterns in JSON-using
applications, while still having a clear correspondence to programming languages
in widespread use. Thus, JTD supports:</t>
<t><list style="symbols">
<t>Signed and unsigned 8, 16, and 32-bit integers. A tool which converts JTD
schemas into code can use <spanx style="verb">int8_t</spanx>, <spanx style="verb">uint8_t</spanx>, <spanx style="verb">int16_t</spanx>, etc., or their
equivalents in the target language, to represent these JTD types.</t>
<t>A distinction between <spanx style="verb">float32</spanx> and <spanx style="verb">float64</spanx>. Code generators can use <spanx style="verb">float</spanx>
and <spanx style="verb">double</spanx>, or their equivalents, for these JTD types.</t>
<t>A “properties” form of JSON objects, corresponding to some sort of struct or
record. The “properties” form of JSON objects is akin to a C++ <spanx style="verb">struct</spanx>.</t>
<t>A “values” form of JSON objects, corresponding to some sort of dictionary or
associative array. The “values” form of JSON objects is akin to a C++
<spanx style="verb">std::map</spanx>.</t>
<t>A “discriminator” form of JSON objects, corresponding to a discriminated (or
“tagged”) union. The “discriminator” form of JSON objects is akin to a C++
<spanx style="verb">std::variant</spanx>.</t>
</list></t>
<t>The principle of common patterns in JSON is why JTD does not support 64-bit
integers, as these are usually transmitted over JSON in a non-interoperable
(i.e., ignoring the recommendations in Section 2.2 of <xref target="RFC7493"/>) or mutually
inconsistent ways. <xref target="other-considerations-int64"/> further elaborates on why JTD
does not support 64-bit integers.</t>
<t>The principle of clear correspondence to common programming languages is why JTD
does not support, for example, a data type for integers up to 2**53-1.</t>
<t>It is expected that for many use-cases, a schema language of JTD’s
expressiveness is sufficient. Where a more expressive language is required,
alternatives exist in CDDL and others.</t>
<t>This document does not have IETF consensus and is presented here to facilitate
experimentation with the concept of JTD. The purpose of the experiment is to
gain experience with JTD and to possibly revise this work accordingly. If JTD
is determined to be a valuable and popular approach it may be taken to the IETF
for further discussion and revision.</t>
<t>This document has the following structure:</t>
<t><xref target="syntax"/> defines the syntax of JTD. <xref target="semantics"/> describes the semantics of
JTD; this includes determining whether some data satisfies a schema and what
error indicators should be produced when the data is unsatisfactory.
<xref target="other-considerations"/> discusses why certain features are omitted from JTD.
<xref target="comparison-with-cddl"/> presents various JTD schemas and their CDDL
equivalents.</t>
<section anchor="terminology" title="Terminology">
<t>The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL
NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”,
“MAY”, and “OPTIONAL” in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
<t>The term “JSON Pointer”, when it appears in this document, is to be understood
as it is defined in <xref target="RFC6901"/>.</t>
<t>The terms “object”, “member”, “array”, “number”, “name”, and “string” in this
document are to be interpreted as described in <xref target="RFC8259"/>.</t>
<t>The term “instance”, when it appears in this document, refers to a JSON value
being validated against a JTD schema. This value can be an entire JSON document,
or it can be a value embedded within a JSON document.</t>
</section>
<section anchor="scope-of-experiment" title="Scope of Experiment">
<t>JTD is an experiment. Participation in this experiment consists of using JTD to
validate or document interchanged JSON messages, or in building tooling atop of
JTD. Feedback on the results of this experiment may be e-mailed to the author.
Participants in this experiment are anticipated to mostly be nodes that provide
or consume JSON-based APIs.</t>
<t>Nodes know if they are participating in the experiment if they are validating
JSON messages against a JTD schema, or if they are relying on another node to do
so. Nodes are also participating in the experiment if they are running code
generated from a JTD schema.</t>
<t>The risk of this experiment “escaping” takes the form of a JTD-supporting node
expecting another node, which lacks such support, to validate messages against
some JTD schema. In such a case, the outcome will likely be that the nodes fail
to interchange information correctly.</t>
<t>This experiment will be deemed successful when JTD has been implemented by
multiple independent parties, and these parties successfully use JTD to
facilitate information interchange within their internal systems or between
systems operated by independent parties.</t>
<t>If this experiment is deemed successful, and JTD is determined to be a valuable
and popular approach, it may be taken to the IETF for further discussion and
revision. One possible outcome of this discussion and revision could be that a
working group produces a Standards Track specification of JTD.</t>
<t>Some implementations of JTD, as well as code generators and other tooling
related to JTD, are available at &lt;https://github.com/jsontypedef&gt;.</t>
</section>
</section>
<section anchor="syntax" title="Syntax">
<t>This section describes when a JSON document is a correct JTD schema. Because
Concise Data Definition Language (CDDL) is well-suited to the task of defining
complex JSON formats, such as JTD schemas, this section uses CDDL to describe
the format of JTD schemas.</t>
<t>JTD schemas may recursively contain other schemas. In this document, a “root
schema” is one which is not contained within another schema, i.e. it is
“top-level”.</t>
<t>A JTD schema is a JSON object taking on an appropriate form. JTD schemas may
contain “additional data”, discussed in <xref target="extending-JTD-syntax"/>. Root JTD
schemas may optionally contain definitions (a mapping from names to schemas).</t>
<t>A correct root JTD schema MUST match the <spanx style="verb">root-schema</spanx> CDDL rule described in
this section. A correct non-root JTD schema MUST match the <spanx style="verb">schema</spanx> CDDL rule
described in this section.</t>
<figure title="CDDL definition of a schema" anchor="cddl-schema"><artwork type="cddl"><![CDATA[
; root-schema is identical to schema, but additionally allows for
; definitions.
;
; definitions are prohibited from appearing on non-root schemas.
root-schema = {
? definitions: { * tstr => { schema}},
schema,
}
; schema is the main CDDL rule defining a JTD schema.
;
; All JTD schemas are JSON objects taking on one of eight forms
; listed here.
schema = (
ref //
type //
enum //
elements //
properties //
values //
discriminator //
empty //
)
; shared is a CDDL rule containing properties that all eight schema
; forms share.
shared = (
? metadata: { * tstr => any },
? nullable: bool,
)
; empty describes the "empty" schema form.
empty = shared
; ref describes the "ref" schema form.
;
; There are additional constraints on this form that cannot be
; expressed in CDDL. Section 2.2.2 describes these additional
; constraints in detail.
ref = ( ref: tstr, shared )
; type describes the "type" schema form.
type = (
type: "boolean"
/ "float32"
/ "float64"
/ "int8"
/ "uint8"
/ "int16"
/ "uint16"
/ "int32"
/ "uint32"
/ "string"
/ "timestamp",
shared,
)
; enum describes the "enum" schema form.
;
; There are additional constraints on this form that cannot be
; expressed in CDDL. Section 2.2.4 describes these additional
; constraints in detail.
enum = ( enum: [+ tstr], shared )
; elements describes the "elements" schema form.
elements = ( elements: { schema }, shared )
; properties describes the "properties" schema form.
;
; This CDDL rule is defined so that a schema of the "properties" form
; may omit a member named "properties" or a member named
; "optionalProperties", but not both.
;
; There are additional constraints on this form that cannot be
; expressed in CDDL. Section 2.2.6 describes these additional
; constraints in detail.
properties = (with-properties // with-optional-properties)
with-properties = (
properties: { * tstr => { schema }},
? optionalProperties: { * tstr => { schema }},
? additionalProperties: bool,
shared,
)
with-optional-properties = (
? properties: { * tstr => { schema }},
optionalProperties: { * tstr => { schema }},
? additionalProperties: bool,
shared,
)
; values describes the "values" schema form.
values = ( values: { schema }, shared )
; discriminator describes the "discriminator" schema form.
;
; There are additional constraints on this form that cannot be
; expressed in CDDL. Section 2.2.8 describes these additional
; constraints in detail.
discriminator = (
discriminator: tstr,
; Note well: this rule is defined in terms of the "properties"
; CDDL rule, not the "schema" CDDL rule.
mapping: { * tstr => { properties } }
shared,
)
]]></artwork></figure>
<t>The remainder of this section will describe constraints on JTD schemas which
cannot be expressed in CDDL, and will provide examples of valid and invalid JTD
schemas.</t>
<section anchor="root-vs-non-root-schemas" title="Root vs. non-root schemas">
<t>The <spanx style="verb">root-schema</spanx> rule in <xref target="cddl-schema"/> permits for a member named
<spanx style="verb">definitions</spanx>, but the <spanx style="verb">schema</spanx> rule does not permit for such a member. This
means that only root (i.e., “top-level”) JTD schemas can have a <spanx style="verb">definitions</spanx>
object, and sub-schemas may not.</t>
<t>Thus</t>
<figure><artwork type="json"><![CDATA[
{ "definitions": {} }
]]></artwork></figure>
<t>is a correct JTD schema, but</t>
<figure><artwork type="json"><![CDATA[
{
"definitions": {
"foo": {
"definitions": {}
}
}
}
]]></artwork></figure>
<t>is not, because sub-schemas (such as the object at <spanx style="verb">/definitions/foo</spanx>) must not
have a member named <spanx style="verb">definitions</spanx>.</t>
</section>
<section anchor="forms" title="Forms">
<t>JTD schemas (i.e. JSON objects satisfying the <spanx style="verb">schema</spanx> CDDL rule in
<xref target="cddl-schema"/>) must take on one of eight forms. These forms are defined so as
to be mutually exclusive; a schema cannot satisfy multiple forms at once.</t>
<section anchor="syntax-form-empty" title="Empty">
<t>The <spanx style="verb">empty</spanx> form is defined by the <spanx style="verb">empty</spanx> CDDL rule in <xref target="cddl-schema"/>. The
semantics of the <spanx style="verb">empty</spanx> form are described in <xref target="semantics-form-empty"/>.</t>
<t>Despite the name “empty”, schemas of the <spanx style="verb">empty</spanx> form are not necessarily empty
JSON objects. Like schemas of any of the eight forms, schemas of the <spanx style="verb">empty</spanx>
form may contain members named <spanx style="verb">nullable</spanx> (whose value must be <spanx style="verb">true</spanx> or
<spanx style="verb">false</spanx>) or <spanx style="verb">metadata</spanx> (whose value must be an object) or both.</t>
<t>Thus</t>
<figure><artwork type="json"><![CDATA[
{}
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{ "nullable": true }
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{ "nullable": true, "metadata": { "foo": "bar" }}
]]></artwork></figure>
<t>are correct JTD schemas of the empty form, but</t>
<figure><artwork type="json"><![CDATA[
{ "nullable": "foo" }
]]></artwork></figure>
<t>is not, because the value of the member named <spanx style="verb">nullable</spanx> must be <spanx style="verb">true</spanx> or
<spanx style="verb">false</spanx>.</t>
</section>
<section anchor="syntax-form-ref" title="Ref">
<t>The <spanx style="verb">ref</spanx> form is defined by the <spanx style="verb">ref</spanx> CDDL rule in <xref target="cddl-schema"/>. The
semantics of the <spanx style="verb">ref</spanx> form are described in <xref target="semantics-form-ref"/>.</t>
<t>For a schema of the <spanx style="verb">ref</spanx> form to be correct, the value of the member named
<spanx style="verb">ref</spanx> must refer to one of the definitions found at the root level of the schema
it appears in. More formally, for a schema <spanx style="emph">S</spanx> of the <spanx style="verb">ref</spanx> form:</t>
<t><list style="symbols">
<t>Let <spanx style="emph">B</spanx> be the root schema containing the schema, or the schema itself if it
is a root schema.</t>
<t>Let <spanx style="emph">R</spanx> be the value of the member of <spanx style="emph">S</spanx> with the name <spanx style="verb">ref</spanx>.</t>
</list></t>
<t>If the schema is correct, then <spanx style="emph">B</spanx> MUST have a member <spanx style="emph">D</spanx> with the name
<spanx style="verb">definitions</spanx>, and <spanx style="emph">D</spanx> MUST contain a member whose name equals <spanx style="emph">R</spanx>.</t>
<t>Thus</t>
<figure><artwork type="json"><![CDATA[
{
"definitions": {
"coordinates": {
"properties": {
"lat": { "type": "float32" },
"lng": { "type": "float32" }
}
}
},
"properties": {
"user_location": { "ref": "coordinates" },
"server_location": { "ref": "coordinates" }
}
}
]]></artwork></figure>
<t>is a correct JTD schema, and demonstrates the point of the <spanx style="verb">ref</spanx> form: to avoid
re-defining the same thing twice. However,</t>
<figure><artwork type="json"><![CDATA[
{ "ref": "foo" }
]]></artwork></figure>
<t>is not a correct JTD schema, as there is no top-level <spanx style="verb">definitions</spanx>, and so the
<spanx style="verb">ref</spanx> form cannot be correct. Similarly,</t>
<figure><artwork type="json"><![CDATA[
{ "definitions": { "foo": {}}, "ref": "bar" }
]]></artwork></figure>
<t>is not a correct JTD schema, as there is no member named <spanx style="verb">bar</spanx> in the top-level
<spanx style="verb">definitions</spanx>.</t>
</section>
<section anchor="syntax-form-type" title="Type">
<t>The <spanx style="verb">type</spanx> form is defined by the <spanx style="verb">type</spanx> CDDL rule in <xref target="cddl-schema"/>. The
semantics of the <spanx style="verb">type</spanx> form are described in <xref target="semantics-form-type"/>.</t>
<t>As an example of a correct JTD schema of the <spanx style="verb">type</spanx> form,</t>
<figure><artwork type="json"><![CDATA[
{ "type": "uint8" }
]]></artwork></figure>
<t>is a correct JTD schema, whereas</t>
<figure><artwork type="json"><![CDATA[
{ "type": true }
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{ "type": "foo" }
]]></artwork></figure>
<t>are not correct schemas, as neither <spanx style="verb">true</spanx> nor the JSON string <spanx style="verb">foo</spanx> are in the
list of permitted values of the <spanx style="verb">type</spanx> member described in the <spanx style="verb">type</spanx> CDDL rule
in <xref target="cddl-schema"/>.</t>
</section>
<section anchor="syntax-form-enum" title="Enum">
<t>The <spanx style="verb">enum</spanx> form is defined by the <spanx style="verb">enum</spanx> CDDL rule in <xref target="cddl-schema"/>. The
semantics of the <spanx style="verb">enum</spanx> form are described in <xref target="semantics-form-enum"/>.</t>
<t>For a schema of the <spanx style="verb">enum</spanx> form to be correct, the value of the member named
<spanx style="verb">enum</spanx> must be a nonempty array of strings, and that array must not contain
duplicate values. More formally, for a schema <spanx style="emph">S</spanx> of the <spanx style="verb">enum</spanx> form:</t>
<t><list style="symbols">
<t>Let <spanx style="emph">E</spanx> be the value of the member of <spanx style="emph">S</spanx> with name <spanx style="verb">enum</spanx>.</t>
</list></t>
<t>If the schema is correct, then there MUST NOT exist any pair of elements of <spanx style="emph">E</spanx>
which encode equal string values, where string equality is defined as in Section
8.3 of <xref target="RFC8259"/>.</t>
<t>Thus</t>
<figure><artwork type="json"><![CDATA[
{ "enum": [] }
]]></artwork></figure>
<t>is not a correct JTD schema, as the value of the member named <spanx style="verb">enum</spanx> must be
nonempty, and</t>
<figure><artwork type="json"><![CDATA[
{ "enum": ["a\\b", "a\u005Cb"] }
]]></artwork></figure>
<t>is not a correct JTD schema, as</t>
<figure><artwork type="json"><![CDATA[
"a\\b"
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
"a\u005Cb"
]]></artwork></figure>
<t>encode strings that are equal by the definition of string equality given in
Section 8.3 of <xref target="RFC8259"/>. By contrast,</t>
<figure><artwork type="json"><![CDATA[
{ "enum": ["PENDING", "IN_PROGRESS", "DONE" ]}
]]></artwork></figure>
<t>is an example of a correct JTD schema of the <spanx style="verb">enum</spanx> form.</t>
</section>
<section anchor="syntax-form-elements" title="Elements">
<t>The <spanx style="verb">elements</spanx> form is defined by the <spanx style="verb">elements</spanx> CDDL rule in <xref target="cddl-schema"/>.
The semantics of the <spanx style="verb">elements</spanx> form are described in
<xref target="semantics-form-elements"/>.</t>
<t>As an example of a correct JTD schema of the <spanx style="verb">elements</spanx> form,</t>
<figure><artwork type="json"><![CDATA[
{ "elements": { "type": "uint8" }}
]]></artwork></figure>
<t>is a correct JTD schema, whereas</t>
<figure><artwork type="json"><![CDATA[
{ "elements": true }
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{ "elements": { "type": "foo" } }
]]></artwork></figure>
<t>are not correct schemas, as neither</t>
<figure><artwork type="json"><![CDATA[
true
]]></artwork></figure>
<t>nor</t>
<figure><artwork type="json"><![CDATA[
{ "type": "foo" }
]]></artwork></figure>
<t>are correct JTD schemas, and the value of the member named <spanx style="verb">elements</spanx> must be a
correct JTD schema.</t>
</section>
<section anchor="syntax-form-properties" title="Properties">
<t>The <spanx style="verb">properties</spanx> form is defined by the <spanx style="verb">properties</spanx> CDDL rule in
<xref target="cddl-schema"/>. The semantics of the <spanx style="verb">properties</spanx> form are described in
<xref target="semantics-form-props"/>.</t>
<t>For a schema of the <spanx style="verb">properties</spanx> form to be correct, properties must either be
required (i.e., in <spanx style="verb">properties</spanx>) or optional (i.e., in <spanx style="verb">optionalProperties</spanx>),
but not both. More formally:</t>
<t>If a schema has both a member named <spanx style="verb">properties</spanx> (with value <spanx style="emph">P</spanx>) and another
member named <spanx style="verb">optionalProperties</spanx> (with value <spanx style="emph">O</spanx>), then <spanx style="emph">O</spanx> and <spanx style="emph">P</spanx> MUST NOT
have any member names in common; that is, no member of <spanx style="emph">P</spanx> may have a name equal
to the name of any member of <spanx style="emph">O</spanx>, under the definition of string equality given
in Section 8.3 of <xref target="RFC8259"/>.</t>
<t>Thus</t>
<figure><artwork type="json"><![CDATA[
{
"properties": { "confusing": {} },
"optionalProperties": { "confusing": {} }
}
]]></artwork></figure>
<t>is not a correct JTD schema, as <spanx style="verb">confusing</spanx> appears in both <spanx style="verb">properties</spanx> and
<spanx style="verb">optionalProperties</spanx>. By contrast,</t>
<figure><artwork type="json"><![CDATA[
{
"properties": {
"users": {
"elements": {
"properties": {
"id": { "type": "string" },
"name": { "type": "string" },
"create_time": { "type": "timestamp" }
},
"optionalProperties": {
"delete_time": { "type": "timestamp" }
}
}
},
"next_page_token": { "type": "string" }
}
}
]]></artwork></figure>
<t>is a correct JTD schema of the <spanx style="verb">properties</spanx> form, describing a paginated list of
users and demonstrating the recursive nature of the syntax of JTD schemas.</t>
</section>
<section anchor="syntax-form-values" title="Values">
<t>The <spanx style="verb">values</spanx> form is defined by the <spanx style="verb">values</spanx> CDDL rule in <xref target="cddl-schema"/>. The
semantics of the <spanx style="verb">values</spanx> form are described in <xref target="semantics-form-values"/>.</t>
<t>As an example of a correct JTD schema of the <spanx style="verb">values</spanx> form,</t>
<figure><artwork type="json"><![CDATA[
{ "values": { "type": "uint8" }}
]]></artwork></figure>
<t>is a correct JTD schema, whereas</t>
<figure><artwork type="json"><![CDATA[
{ "values": true }
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{ "values": { "type": "foo" } }
]]></artwork></figure>
<t>are not correct schemas, as neither</t>
<figure><artwork type="json"><![CDATA[
true
]]></artwork></figure>
<t>nor</t>
<figure><artwork type="json"><![CDATA[
{ "type": "foo" }
]]></artwork></figure>
<t>are correct JTD schemas, and the value of the member named <spanx style="verb">values</spanx> must be a
correct JTD schema.</t>
</section>
<section anchor="syntax-form-discriminator" title="Discriminator">
<t>The <spanx style="verb">discriminator</spanx> form is defined by the <spanx style="verb">discriminator</spanx> CDDL rule in
<xref target="cddl-schema"/>. The semantics of the <spanx style="verb">discriminator</spanx> form are described in
<xref target="semantics-form-discriminator"/>. Understanding the semantics of the
<spanx style="verb">discriminator</spanx> form will likely aid the reader in understanding why this
section provides constraints on the <spanx style="verb">discriminator</spanx> form beyond those in
<xref target="cddl-schema"/>.</t>
<t>To prevent ambiguous or unsatisfiable constraints on the <spanx style="verb">discriminator</spanx>
property of a tagged union, an additional constraint on schemas of the
<spanx style="verb">discriminator</spanx> form exists. For schemas of the discriminator form:</t>
<t><list style="symbols">
<t>Let <spanx style="emph">D</spanx> be the member of the schema with the name <spanx style="verb">discriminator</spanx>.</t>
<t>Let <spanx style="emph">M</spanx> be the member of the schema with the name <spanx style="verb">mapping</spanx>.</t>
</list></t>
<t>If the schema is correct, then all member values <spanx style="emph">S</spanx> of <spanx style="emph">M</spanx> will be schemas of
the “properties” form. For each <spanx style="emph">S</spanx>:</t>
<t><list style="symbols">
<t>If <spanx style="emph">S</spanx> has a member <spanx style="emph">N</spanx> whose name equals <spanx style="verb">nullable</spanx>, <spanx style="emph">N</spanx>’s value MUST NOT be
the JSON primitive value <spanx style="verb">true</spanx>.</t>
<t>For each member <spanx style="emph">P</spanx> of <spanx style="emph">S</spanx> whose name equals <spanx style="verb">properties</spanx> or
<spanx style="verb">optionalProperties</spanx>, <spanx style="emph">P</spanx>’s value, which must be an object, MUST NOT contain
any members whose name equals <spanx style="emph">D</spanx>’s value.</t>
</list></t>
<t>Thus</t>
<figure><artwork type="json"><![CDATA[
{
"discriminator": "event_type",
"mapping": {
"can_the_object_be_null_or_not?": {
"nullable": true,
"properties": { "foo": { "type": "string" } }}
}
}
}
]]></artwork></figure>
<t>is an incorrect schema, as a member of <spanx style="verb">mapping</spanx> has a member named <spanx style="verb">nullable</spanx>
whose value is <spanx style="verb">true</spanx>. This would suggest that the instance may be null. Yet the
top-level schema lacks such a <spanx style="verb">nullable</spanx> set to <spanx style="verb">true</spanx>, which would suggest that
the instance in fact cannot be null. If this were a correct JTD schema, it would
be unclear which piece of information takes “precedence”.</t>
<t>JTD handles such possible ambiguity by disallowing, at the syntactic level, the
possibility of contradictory specifications of whether an instance described by
a schema of the <spanx style="verb">discriminator</spanx> form may be null. The schemas in a discriminator
<spanx style="verb">mapping</spanx> cannot have <spanx style="verb">nullable</spanx> set to <spanx style="verb">true</spanx>; only the discriminator itself
can use <spanx style="verb">nullable</spanx> in this way.</t>
<t>It also follows that</t>
<figure><artwork type="json"><![CDATA[
{
"discriminator": "event_type",
"mapping": {
"is_event_type_a_string_or_a_float32?": {
"properties": { "event_type": { "type": "float32" }}
}
}
}
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{
"discriminator": "event_type",
"mapping": {
"is_event_type_a_string_or_an_optional_float32?": {
"optionalProperties": { "event_type": { "type": "float32" }}
}
}
}
]]></artwork></figure>
<t>are incorrect schemas, as <spanx style="verb">event_type</spanx> is both the value of <spanx style="verb">discriminator</spanx> and
a member name in one of the <spanx style="verb">mapping</spanx> member <spanx style="verb">properties</spanx> or
<spanx style="verb">optionalProperties</spanx>. This is ambiguous, because ordinarily the <spanx style="verb">discriminator</spanx>
keyword would indicate that <spanx style="verb">event_type</spanx> is expected to be a string, but another
part of the schema specifies that <spanx style="verb">event_type</spanx> is expected to be a number.</t>
<t>JTD handles such possible ambiguity by disallowing, at the syntactic level, the
possibility of contradictory specifications of discriminator “tags”.
Discriminator “tags” cannot be re-defined in other parts of the schema.</t>
<t>By contrast,</t>
<figure><artwork type="json"><![CDATA[
{
"tag": "event_type",
"mapping": {
"account_deleted": {
"properties": {
"account_id": { "type": "string" }
}
},
"account_payment_plan_changed": {
"properties": {
"account_id": { "type": "string" },
"payment_plan": { "enum": ["FREE", "PAID"] }
},
"optionalProperties": {
"upgraded_by": { "type": "string" }
}
}
}
}
]]></artwork></figure>
<t>is a correct schema, describing a pattern of data common in JSON-based messaging
systems. <xref target="semantics-form-discriminator"/> provides examples of what this schema
accepts and rejects.</t>
</section>
</section>
<section anchor="extending-JTD-syntax" title="Extending JTD’s Syntax">
<t>This document does not describe any extension mechanisms for JTD schema
validation, which is described in <xref target="semantics"/>. However, schemas are defined to
optionally contain a <spanx style="verb">metadata</spanx> keyword, whose value is an arbitrary JSON
object. Call the members of this object “metadata members”.</t>
<t>Users MAY add metadata members to JTD schemas to convey information that is not
pertinent to validation. For example, such metadata members could provide hints
to code generators, or trigger some special behavior for a library that
generates user interfaces from schemas.</t>
<t>Users SHOULD NOT expect metadata members to be understood by other parties. As a
result, if consistent validation with other parties is a requirement, users MUST
NOT use metadata members to affect how schema validation, as described in
<xref target="semantics"/>, works.</t>
<t>Users MAY expect metadata members to be understood by other parties, and MAY use
metadata members to affect how schema validation works, if these other parties
are somehow known to support these metadata members. For example, two parties
may agree, out of band, that they will support an extended JTD with a custom
metadata member that affects validation.</t>
</section>
</section>
<section anchor="semantics" title="Semantics">
<t>This section describes when an instance is valid against a correct JTD schema,
and the error indicators to produce when an instance is invalid.</t>
<section anchor="allow-additional-properties" title="Allowing Additional Properties">
<t>Users will have different desired behavior with respect to “unspecified” members
in an instance. For example, consider the JTD schema in <xref target="JTD-properties-a"/>:</t>
<figure title="An illustrative JTD schema" anchor="JTD-properties-a"><artwork type="json"><![CDATA[
{ "properties": { "a": { "type": "string" }}}
]]></artwork></figure>
<t>Some users may expect that</t>
<figure><artwork type="json"><![CDATA[
{"a": "foo", "b": "bar"}
]]></artwork></figure>
<t>satisfies the schema in <xref target="JTD-properties-a"/>. Others may disagree, as <spanx style="verb">b</spanx> is
not one of the properties described in the schema. In this document, allowing
such “unspecified” members, like <spanx style="verb">b</spanx> in this example, happens when evaluation is
in “allow additional properties” mode.</t>
<t>Evaluation of a schema does not allow additional properties by default, but can
be overridden by having the schema include a member named
<spanx style="verb">additionalProperties</spanx>, where that member has a value of <spanx style="verb">true</spanx>.</t>
<t>More formally: evaluation of a schema <spanx style="emph">S</spanx> is in “allow additional properties”
mode if there exists a member of <spanx style="emph">S</spanx> whose name equals <spanx style="verb">additionalProperties</spanx>,
and whose value is a boolean <spanx style="verb">true</spanx>. Otherwise, evaluation of <spanx style="emph">S</spanx> is not in
“allow additional properties” mode.</t>
<t>See <xref target="semantics-form-props"/> for how allowing unknown properties affects schema
evaluation, but briefly, the schema</t>
<figure><artwork type="json"><![CDATA[
{ "properties": { "a": { "type": "string" }}}
]]></artwork></figure>
<t>rejects</t>
<figure><artwork type="json"><![CDATA[
{ "a": "foo", "b": "bar" }
]]></artwork></figure>
<t>However, the schema</t>
<figure><artwork type="json"><![CDATA[
{
"additionalProperties": true,
"properties": { "a": { "type": "string" }}
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
{ "a": "foo", "b": "bar" }
]]></artwork></figure>
<t>Note that <spanx style="verb">additionalProperties</spanx> does not get “inherited” by sub-schemas. For
example, the JTD schema</t>
<figure><artwork type="json"><![CDATA[
{
"additionalProperties": true,
"properties": {
"a": {
"properties": {
"b": { "type": "string" }
}
}
}
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
{ "a": { "b": "c" }, "foo": "bar" }
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
{ "a": { "b": "c", "foo": "bar" }}
]]></artwork></figure>
<t>because the <spanx style="verb">additionalProperties</spanx> at the root level does not affect the
behavior of sub-schemas.</t>
<t>Note from <xref target="cddl-schema"/> that only schemas of the <spanx style="verb">properties</spanx> form may have a
member named <spanx style="verb">additionalProperties</spanx>.</t>
</section>
<section anchor="errors" title="Errors">
<t>To facilitate consistent validation error handling, this document specifies a
standard error indicator format. Implementations SHOULD support producing error
indicators in this standard form.</t>
<t>The standard error indicator format is a JSON array. The order of the elements
of this array is not specified. The elements of this array are JSON objects
with:</t>
<t><list style="symbols">
<t>A member with the name <spanx style="verb">instancePath</spanx>, whose value is a JSON string encoding a
JSON Pointer. This JSON Pointer will point to the part of the instance that
was rejected.</t>
<t>A member with the name <spanx style="verb">schemaPath</spanx>, whose value is a JSON string encoding a
JSON Pointer. This JSON Pointer will point to the part of the schema that
rejected the instance.</t>
</list></t>
<t>The values for <spanx style="verb">instancePath</spanx> and <spanx style="verb">schemaPath</spanx> depend on the form of the schema,
and are described in detail in <xref target="semantics-forms"/>.</t>
</section>
<section anchor="semantics-forms" title="Forms">
<t>This section describes, for each of the eight JTD schema forms, the rules
dictating whether an instance is accepted, as well as the error indicators to
produce when an instance is invalid.</t>
<t>The forms a correct schema may take on are formally described in <xref target="syntax"/>.</t>
<section anchor="semantics-form-empty" title="Empty">
<t>The <spanx style="verb">empty</spanx> form is meant to describe instances whose values are unknown,
unpredictable, or otherwise unconstrained by the schema. The syntax of the
<spanx style="verb">empty</spanx> form is described in <xref target="syntax-form-empty"/>.</t>
<t>If a schema is of the empty form, then it accepts all instances. A schema of the
empty form will never produce any error indicators.</t>
</section>
<section anchor="semantics-form-ref" title="Ref">
<t>The <spanx style="verb">ref</spanx> form is for when a schema is defined in terms of something in the
<spanx style="verb">definitions</spanx> of the root schema. The ref form enables schemas to be less
repetitive, and also enables describing recursive structures. The syntax of the
<spanx style="verb">ref</spanx> form is described in <xref target="syntax-form-ref"/>.</t>
<t>If a schema is of the ref form, then:</t>
<t><list style="symbols">
<t>If the schema has a member named <spanx style="verb">nullable</spanx> whose value is the boolean <spanx style="verb">true</spanx>,
and the instance is the JSON primitive value <spanx style="verb">null</spanx>, then the schema accepts
the instance. Otherwise:</t>
<t>Let <spanx style="emph">B</spanx> be the root schema containing the schema, or the schema itself if it
is a root schema.</t>
<t>Let <spanx style="emph">D</spanx> be the member of <spanx style="emph">B</spanx> with the name <spanx style="verb">definitions</spanx>. By <xref target="syntax"/>, <spanx style="emph">D</spanx>
exists.</t>
<t>Let <spanx style="emph">R</spanx> be the value of the schema member with the name <spanx style="verb">ref</spanx>.</t>
<t>Let <spanx style="emph">S</spanx> be the value of the member of <spanx style="emph">D</spanx> whose name equals <spanx style="emph">R</spanx>. By
<xref target="syntax-form-ref"/>, <spanx style="emph">S</spanx> exists, and is a schema.</t>
</list></t>
<t>The schema accepts the instance if and only if <spanx style="emph">S</spanx> accepts the instance.
Otherwise, the error indicators to return in this case are the union of the
error indicators from evaluating <spanx style="emph">S</spanx> against the instance.</t>
<t>For example, the schema:</t>
<figure><artwork type="json"><![CDATA[
{
"definitions": { "a": { "type": "float32" }},
"ref": "a"
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
123
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/definitions/a/type" }]
]]></artwork></figure>
<t>The schema</t>
<figure><artwork type="json"><![CDATA[
{
"definitions": { "a": { "type": "float32" }},
"ref": "a",
"nullable": true
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>because the schema has a <spanx style="verb">nullable</spanx> member, whose value is <spanx style="verb">true</spanx>.</t>
<t>Note that <spanx style="verb">nullable</spanx> being <spanx style="verb">false</spanx> has no effect in any of the forms described
in this document. For example, the schema</t>
<figure><artwork type="json"><![CDATA[
{
"definitions": { "a": { "nullable": false, "type": "float32" }},
"ref": "a",
"nullable": true
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>In other words, it is not the case that putting a <spanx style="verb">false</spanx> value for <spanx style="verb">nullable</spanx>
will ever “override” a <spanx style="verb">nullable</spanx> member in schemas of the <spanx style="verb">ref</spanx> form; it is
correct, though ineffectual, to have a value of <spanx style="verb">false</spanx> for the <spanx style="verb">nullable</spanx>
member in a schema.</t>
</section>
<section anchor="semantics-form-type" title="Type">
<t>The <spanx style="verb">type</spanx> form is meant to describe instances whose value is a boolean, number,
string, or timestamp (<xref target="RFC3339"/>). The syntax of the <spanx style="verb">type</spanx> form is described
in <xref target="syntax-form-type"/>.</t>
<t>If a schema is of the type form, then:</t>
<t><list style="symbols">
<t>If the schema has a member named <spanx style="verb">nullable</spanx> whose value is the boolean <spanx style="verb">true</spanx>,
and the instance is the JSON primitive value <spanx style="verb">null</spanx>, then the schema accepts
the instance. Otherwise:</t>
<t>Let <spanx style="emph">T</spanx> be the value of the member with the name <spanx style="verb">type</spanx>. The following table
describes whether the instance is accepted, as a function of <spanx style="emph">T</spanx>’s value:</t>
</list></t>
<texttable title="Accepted Values for Type" anchor="type-values">
<ttcol align='left'>If _T_ equals …</ttcol>
<ttcol align='left'>then the instance is accepted if it is …</ttcol>
<c>boolean</c>
<c>equal to <spanx style="verb">true</spanx> or <spanx style="verb">false</spanx></c>
<c>float32</c>
<c>a JSON number</c>
<c>float64</c>
<c>a JSON number</c>
<c>int8</c>
<c>See <xref target="int-ranges"/></c>
<c>uint8</c>
<c>See <xref target="int-ranges"/></c>
<c>int16</c>
<c>See <xref target="int-ranges"/></c>
<c>uint16</c>
<c>See <xref target="int-ranges"/></c>
<c>int32</c>
<c>See <xref target="int-ranges"/></c>
<c>uint32</c>
<c>See <xref target="int-ranges"/></c>
<c>string</c>
<c>a JSON string</c>
<c>timestamp</c>
<c>a JSON string that follows the standard format described in <xref target="RFC3339"/>, as refined by Section 3.3 of <xref target="RFC4287"/></c>
</texttable>
<t><spanx style="verb">float32</spanx> and <spanx style="verb">float64</spanx> are distinguished from each other in their intent.
<spanx style="verb">float32</spanx> indicates data intended to be processed as an IEEE 754
single-precision float, whereas <spanx style="verb">float64</spanx> indicates data intended to be
processed as an IEEE 754 double-precision float. Tools which generate code from
JTD schemas will likely produce different code for <spanx style="verb">float32</spanx> than for
<spanx style="verb">float64</spanx>.</t>
<t>If <spanx style="emph">T</spanx> starts with <spanx style="verb">int</spanx> or <spanx style="verb">uint</spanx>, then the instance is accepted if and only if
it is a JSON number encoding a value with zero fractional part. Depending on the
value of <spanx style="emph">T</spanx>, this encoded number must additionally fall within a particular
range:</t>
<texttable title="Ranges for Integer Types" anchor="int-ranges">
<ttcol align='left'>_T_</ttcol>
<ttcol align='left'>Minimum Value (Inclusive)</ttcol>
<ttcol align='left'>Maximum Value (Inclusive)</ttcol>
<c>int8</c>
<c>-128</c>
<c>127</c>
<c>uint8</c>
<c>0</c>
<c>255</c>
<c>int16</c>
<c>-32,768</c>
<c>32,767</c>
<c>uint16</c>
<c>0</c>
<c>65,535</c>
<c>int32</c>
<c>-2,147,483,648</c>
<c>2,147,483,647</c>
<c>uint32</c>
<c>0</c>
<c>4,294,967,295</c>
</texttable>
<t>Note that</t>
<figure><artwork type="json"><![CDATA[
10
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
10.0
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
1.0e1
]]></artwork></figure>
<t>encode values with zero fractional part, whereas</t>
<figure><artwork type="json"><![CDATA[
10.5
]]></artwork></figure>
<t>encodes a number with a non-zero fractional part. Thus the schema</t>
<figure><artwork type="json"><![CDATA[
{"type": "int8"}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
10
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
10.0
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
1.0e1
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
10.5
]]></artwork></figure>
<t>as well as</t>
<figure><artwork type="json"><![CDATA[
false
]]></artwork></figure>
<t>because “false” is not a number at all.</t>
<t>If the instance is not accepted, then the error indicator for this case shall
have an <spanx style="verb">instancePath</spanx> pointing to the instance, and a <spanx style="verb">schemaPath</spanx> pointing to
the schema member with the name <spanx style="verb">type</spanx>.</t>
<t>For example, the schema:</t>
<figure><artwork type="json"><![CDATA[
{"type": "boolean"}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
false
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
127
]]></artwork></figure>
<t>The schema:</t>
<figure><artwork type="json"><![CDATA[
{"type": "float32"}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
10.5
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
127
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
false
]]></artwork></figure>
<t>The schema:</t>
<figure><artwork type="json"><![CDATA[
{"type": "string"}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
"1985-04-12T23:20:50.52Z"
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
"foo"
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
false
]]></artwork></figure>
<t>The schema:</t>
<figure><artwork type="json"><![CDATA[
{"type": "timestamp"}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
"1985-04-12T23:20:50.52Z"
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
"foo"
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
false
]]></artwork></figure>
<t>The schema:</t>
<figure><artwork type="json"><![CDATA[
{"type": "boolean", "nullable": true}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
false
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
127
]]></artwork></figure>
<t>In all of the examples of rejected instances given in this section, the error
indicator to produce is:</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/type" }]
]]></artwork></figure>
</section>
<section anchor="semantics-form-enum" title="Enum">
<t>The <spanx style="verb">enum</spanx> form is meant to describe instances whose value must be one of a
given set of string values. The syntax of the <spanx style="verb">enum</spanx> form is described in
<xref target="syntax-form-enum"/>.</t>
<t>If a schema is of the enum form, then:</t>
<t><list style="symbols">
<t>If the schema has a member named <spanx style="verb">nullable</spanx> whose value is the boolean <spanx style="verb">true</spanx>,
and the instance is the JSON primitive value <spanx style="verb">null</spanx>, then the schema accepts
the instance. Otherwise:</t>
<t>Let <spanx style="emph">E</spanx> be the value of the schema member with the name <spanx style="verb">enum</spanx>. The instance
is accepted if and only if it is equal to one of the elements of <spanx style="emph">E</spanx>.</t>
</list></t>
<t>If the instance is not accepted, then the error indicator for this case shall
have an <spanx style="verb">instancePath</spanx> pointing to the instance, and a <spanx style="verb">schemaPath</spanx> pointing to
the schema member with the name <spanx style="verb">enum</spanx>.</t>
<t>For example, the schema:</t>
<figure><artwork type="json"><![CDATA[
{ "enum": ["PENDING", "DONE", "CANCELED"] }
]]></artwork></figure>
<t>Accepts</t>
<figure><artwork type="json"><![CDATA[
"PENDING"
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
"DONE"
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
"CANCELED"
]]></artwork></figure>
<t>but rejects all of</t>
<figure><artwork type="json"><![CDATA[
0
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
1
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
2
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
"UNKNOWN"
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>with the error indicator:</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/enum" }]
]]></artwork></figure>
<t>The schema</t>
<figure><artwork type="json"><![CDATA[
{ "enum": ["PENDING", "DONE", "CANCELED"], "nullable": true }
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
"PENDING"
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
1
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
"UNKNOWN"
]]></artwork></figure>
<t>with the error indicator:</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/enum" }]
]]></artwork></figure>
</section>
<section anchor="semantics-form-elements" title="Elements">
<t>The <spanx style="verb">elements</spanx> form is meant to describe instances that must be arrays. A
further sub-schema describes the elements of the array. The syntax of the
<spanx style="verb">elements</spanx> form is described in <xref target="syntax-form-elements"/>.</t>
<t>If a schema is of the elements form, then:</t>
<t><list style="symbols">
<t>If the schema has a member named <spanx style="verb">nullable</spanx> whose value is the boolean <spanx style="verb">true</spanx>,
and the instance is the JSON primitive value <spanx style="verb">null</spanx>, then the schema accepts
the instance. Otherwise:</t>
<t>Let <spanx style="emph">S</spanx> be the value of the schema member with the name <spanx style="verb">elements</spanx>. The
instance is accepted if and only if all of the following are true: <list style="symbols">
<t>The instance is an array. Otherwise, the error indicator for this case shall
have an <spanx style="verb">instancePath</spanx> pointing to the instance, and a <spanx style="verb">schemaPath</spanx> pointing
to the schema member with the name <spanx style="verb">elements</spanx>.</t>
<t>If the instance is an array, then every element of the instance must be
accepted by <spanx style="emph">S</spanx>. Otherwise, the error indicators for this case are the union
of all the errors arising from evaluating <spanx style="emph">S</spanx> against elements of the
instance.</t>
</list></t>
</list></t>
<t>For example, the schema:</t>
<figure><artwork type="json"><![CDATA[
{
"elements": {
"type": "float32"
}
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
[]
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
[1, 2, 3]
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>with the error indicator:</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/elements" }]
]]></artwork></figure>
<t>and rejects</t>
<figure><artwork type="json"><![CDATA[
[1, 2, "foo", 3, "bar"]
]]></artwork></figure>
<t>with the error indicators:</t>
<figure><artwork type="json"><![CDATA[
[
{ "instancePath": "/2", "schemaPath": "/elements/type" },
{ "instancePath": "/4", "schemaPath": "/elements/type" }
]
]]></artwork></figure>
<t>The schema</t>
<figure><artwork type="json"><![CDATA[
{
"elements": {
"type": "float32"
},
"nullable": true
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
[]
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
[1, 2, 3]
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
[1, 2, "foo", 3, "bar"]
]]></artwork></figure>
<t>with the error indicators:</t>
<figure><artwork type="json"><![CDATA[
[
{ "instancePath": "/2", "schemaPath": "/elements/type" },
{ "instancePath": "/4", "schemaPath": "/elements/type" }
]
]]></artwork></figure>
</section>
<section anchor="semantics-form-props" title="Properties">
<t>The <spanx style="verb">properties</spanx> form is meant to describe JSON objects being used as a
“struct”. The syntax of the <spanx style="verb">properties</spanx> form is described in
<xref target="syntax-form-properties"/>.</t>
<t>If a schema is of the properties form, then:</t>
<t><list style="symbols">
<t>If the schema has a member named <spanx style="verb">nullable</spanx> whose value is the boolean <spanx style="verb">true</spanx>,
and the instance is the JSON primitive value <spanx style="verb">null</spanx>, then the schema accepts
the instance. Otherwise the instance is accepted if and only if all of the
following are true:</t>
<t>The instance is an object. <vspace blankLines='1'/>
Otherwise, the error indicator for this case shall have an <spanx style="verb">instancePath</spanx>
pointing to the instance, and a <spanx style="verb">schemaPath</spanx> pointing to the schema member
with the name <spanx style="verb">properties</spanx> if such a schema member exists; if such a member
doesn’t exist, <spanx style="verb">schemaPath</spanx> shall point to the schema member with the name
<spanx style="verb">optionalProperties</spanx>.</t>
<t>If the instance is an object and the schema has a member named <spanx style="verb">properties</spanx>,
then let <spanx style="emph">P</spanx> be the value of the schema member named <spanx style="verb">properties</spanx>. <spanx style="emph">P</spanx>, by
<xref target="syntax-form-properties"/>, must be an object. For every member name in <spanx style="emph">P</spanx>, a
member of the same name in the instance must exist. <vspace blankLines='1'/>
Otherwise, the error indicator for this case shall have an <spanx style="verb">instancePath</spanx>
pointing to the instance, and a <spanx style="verb">schemaPath</spanx> pointing to the member of <spanx style="emph">P</spanx>
failing the requirement just described.</t>
<t>If the instance is an object, then let <spanx style="emph">P</spanx> be the value of the schema member
named <spanx style="verb">properties</spanx> (if it exists), and <spanx style="emph">O</spanx> be the value of the schema member
named <spanx style="verb">optionalProperties</spanx> (if it exists). <vspace blankLines='1'/>
For every member <spanx style="emph">I</spanx> of the instance, find a member with the same name as
<spanx style="emph">I</spanx>’s in <spanx style="emph">P</spanx> or <spanx style="emph">O</spanx>. By <xref target="syntax-form-properties"/>, it is not possible for
both <spanx style="emph">P</spanx> and <spanx style="emph">O</spanx> to have such a member. If the “discriminator tag exemption”
is in effect on <spanx style="emph">I</spanx> (see <xref target="semantics-form-discriminator"/>), then ignore <spanx style="emph">I</spanx>.
Otherwise: <list style="symbols">
<t>If no such member in <spanx style="emph">P</spanx> or <spanx style="emph">O</spanx> exists and validation is not in “allow
additional properties” mode (see <xref target="allow-additional-properties"/>), then the
instance is rejected. <vspace blankLines='1'/>
The error indicator for this case has an <spanx style="verb">instancePath</spanx> pointing to <spanx style="emph">I</spanx>, and
a <spanx style="verb">schemaPath</spanx> pointing to the schema.</t>
<t>If such a member in <spanx style="emph">P</spanx> or <spanx style="emph">O</spanx> does exist, then call this member <spanx style="emph">S</spanx>. If <spanx style="emph">S</spanx>
rejects <spanx style="emph">I</spanx>’s value, then the instance is rejected. <vspace blankLines='1'/>
The error indicators for this case are the union of the error indicators
from evaluating <spanx style="emph">S</spanx> against <spanx style="emph">I</spanx>’s value.</t>
</list></t>
</list></t>
<t>An instance may have multiple errors arising from the third and fourth bullet in
the above. In this case, the error indicators are the union of the errors.</t>
<t>For example, the schema:</t>
<figure><artwork type="json"><![CDATA[
{
"properties": {
"a": { "type": "string" },
"b": { "type": "string" }
},
"optionalProperties": {
"c": { "type": "string" },
"d": { "type": "string" }
}
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
{ "a": "foo", "b": "bar" }
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{ "a": "foo", "b": "bar", "c": "baz" }
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{ "a": "foo", "b": "bar", "c": "baz", "d": "quux" }
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{ "a": "foo", "b": "bar", "d": "quux" }
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/properties" }]
]]></artwork></figure>
<t>and rejects</t>
<figure><artwork type="json"><![CDATA[
{ "b": 3, "c": 3, "e": 3 }
]]></artwork></figure>
<t>with the error indicators</t>
<figure><artwork type="json"><![CDATA[
[
{ "instancePath": "",
"schemaPath": "/properties/a" },
{ "instancePath": "/b",
"schemaPath": "/properties/b/type" },
{ "instancePath": "/c",
"schemaPath": "/optionalProperties/c/type" },
{ "instancePath": "/e",
"schemaPath": "" }
]
]]></artwork></figure>
<t>If instead the schema had <spanx style="verb">additionalProperties: true</spanx>, but was otherwise the
same:</t>
<figure><artwork type="json"><![CDATA[
{
"properties": {
"a": { "type": "string" },
"b": { "type": "string" }
},
"optionalProperties": {
"c": { "type": "string" },
"d": { "type": "string" }
},
"additionalProperties": true
}
]]></artwork></figure>
<t>And the instance remained the same:</t>
<figure><artwork type="json"><![CDATA[
{ "b": 3, "c": 3, "e": 3 }
]]></artwork></figure>
<t>Then the error indicators from evaluating the instance against the schema would
be:</t>
<figure><artwork type="json"><![CDATA[
[
{ "instancePath": "",
"schemaPath": "/properties/a" },
{ "instancePath": "/b",
"schemaPath": "/properties/b/type" },
{ "instancePath": "/c",
"schemaPath": "/optionalProperties/c/type" },
]
]]></artwork></figure>
<t>These are the same errors as before, except the final error (associated with the
additional member named <spanx style="verb">e</spanx> in the instance) is no longer present. This is
because <spanx style="verb">additionalProperties: true</spanx> enables “allow additional properties” mode
on the schema.</t>
<t>Finally, the schema:</t>
<figure><artwork type="json"><![CDATA[
{
"nullable": true,
"properties": {
"a": { "type": "string" },
"b": { "type": "string" }
},
"optionalProperties": {
"c": { "type": "string" },
"d": { "type": "string" }
},
"additionalProperties": true
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
{ "b": 3, "c": 3, "e": 3 }
]]></artwork></figure>
<t>with the error indicators</t>
<figure><artwork type="json"><![CDATA[
[
{ "instancePath": "",
"schemaPath": "/properties/a" },
{ "instancePath": "/b",
"schemaPath": "/properties/b/type" },
{ "instancePath": "/c",
"schemaPath": "/optionalProperties/c/type" },
]
]]></artwork></figure>
</section>
<section anchor="semantics-form-values" title="Values">
<t>The <spanx style="verb">values</spanx> form is meant to describe instances that are JSON objects being
used as an associative array. The syntax of the <spanx style="verb">values</spanx> form is described in
<xref target="syntax-form-values"/>.</t>
<t>If a schema is of the values form, then:</t>
<t><list style="symbols">
<t>If the schema has a member named <spanx style="verb">nullable</spanx> whose value is the boolean <spanx style="verb">true</spanx>,
and the instance is the JSON primitive value <spanx style="verb">null</spanx>, then the schema accepts
the instance. Otherwise:</t>
<t>Let <spanx style="emph">S</spanx> be the value of the schema member with the name <spanx style="verb">values</spanx>. The instance
is accepted if and only if all of the following are true: <list style="symbols">
<t>The instance is an object. Otherwise, the error indicator for this case
shall have an <spanx style="verb">instancePath</spanx> pointing to the instance, and a <spanx style="verb">schemaPath</spanx>
pointing to the schema member with the name <spanx style="verb">values</spanx>.</t>
<t>If the instance is an object, then every member value of the instance must
be accepted by <spanx style="emph">S</spanx>. Otherwise, the error indicators for this case are the
union of all the error indicators arising from evaluating <spanx style="emph">S</spanx> against member
values of the instance.</t>
</list></t>
</list></t>
<t>For example, the schema:</t>
<figure><artwork type="json"><![CDATA[
{
"values": {
"type": "float32"
}
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
{}
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{"a": 1, "b": 2}
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/values" }]
]]></artwork></figure>
<t>and rejects</t>
<figure><artwork type="json"><![CDATA[
{ "a": 1, "b": 2, "c": "foo", "d": 3, "e": "bar" }
]]></artwork></figure>
<t>with the error indicators</t>
<figure><artwork type="json"><![CDATA[
[
{ "instancePath": "/c", "schemaPath": "/values/type" },
{ "instancePath": "/e", "schemaPath": "/values/type" }
]
]]></artwork></figure>
<t>The schema:</t>
<figure><artwork type="json"><![CDATA[
{
"nullable": true,
"values": {
"type": "float32"
}
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
{ "a": 1, "b": 2, "c": "foo", "d": 3, "e": "bar" }
]]></artwork></figure>
<t>with the error indicators</t>
<figure><artwork type="json"><![CDATA[
[
{ "instancePath": "/c", "schemaPath": "/values/type" },
{ "instancePath": "/e", "schemaPath": "/values/type" }
]
]]></artwork></figure>
</section>
<section anchor="semantics-form-discriminator" title="Discriminator">
<t>The <spanx style="verb">discriminator</spanx> form is meant to describe JSON objects being used in a
fashion similar to a discriminated union construct in C-like languages. The
syntax of the <spanx style="verb">discriminator</spanx> form is described in
<xref target="syntax-form-discriminator"/>.</t>
<t>When a schema is of the “discriminator” form, it validates:</t>
<t><list style="symbols">
<t>That the instance is an object,</t>
<t>That the instance has a particular “tag” property,</t>
<t>That this “tag” property’s value is a string within a set of valid values, and</t>
<t>That the instance satisfies another schema, where this other schema is chosen
based on the value of the “tag” property.</t>
</list></t>
<t>The behavior of the discriminator form is more complex than the other keywords.
Readers familiar with CDDL may find the final example in
<xref target="comparison-with-cddl"/> helpful in understanding its behavior. What follows in
this section is a description of the discriminator form’s behavior, as well as
some examples.</t>
<t>If a schema is of the “discriminator” form, then:</t>
<t><list style="symbols">
<t>Let <spanx style="emph">D</spanx> be the schema member with the name <spanx style="verb">discriminator</spanx>.</t>
<t>Let <spanx style="emph">M</spanx> be the schema member with the name <spanx style="verb">mapping</spanx>.</t>
<t>Let <spanx style="emph">I</spanx> be the instance member whose name equals <spanx style="emph">D</spanx>’s value. <spanx style="emph">I</spanx> may, for
some rejected instances, not exist.</t>
<t>Let <spanx style="emph">S</spanx> be the member of <spanx style="emph">M</spanx> whose name equals <spanx style="emph">I</spanx>’s value. <spanx style="emph">S</spanx> may, for some
rejected instances, not exist.</t>
</list></t>
<t>If the schema has a member named <spanx style="verb">nullable</spanx> whose value is the boolean <spanx style="verb">true</spanx>,
and the instance is the JSON primitive value <spanx style="verb">null</spanx>, then the schema accepts the
instance. Otherwise the instance is accepted if and only if all of the following
are true:</t>
<t><list style="symbols">
<t>The instance is an object. <vspace blankLines='1'/>
Otherwise, the error indicator for this case shall have an <spanx style="verb">instancePath</spanx>
pointing to the instance, and a <spanx style="verb">schemaPath</spanx> pointing to <spanx style="emph">D</spanx>.</t>
<t>If the instance is a JSON object, then <spanx style="emph">I</spanx> must exist. <vspace blankLines='1'/>
Otherwise, the error indicator for this case shall have an <spanx style="verb">instancePath</spanx>
pointing to the instance, and a <spanx style="verb">schemaPath</spanx> pointing to <spanx style="emph">D</spanx>.</t>
<t>If the instance is a JSON object and <spanx style="emph">I</spanx> exists, <spanx style="emph">I</spanx>’s value must be a string. <vspace blankLines='1'/>
Otherwise, the error indicator for this case shall have an <spanx style="verb">instancePath</spanx>
pointing to <spanx style="emph">I</spanx>, and a <spanx style="verb">schemaPath</spanx> pointing to <spanx style="emph">D</spanx>.</t>
<t>If the instance is a JSON object and <spanx style="emph">I</spanx> exists and has a string value, then
<spanx style="emph">S</spanx> must exist. <vspace blankLines='1'/>
Otherwise, the error indicator for this case shall have an <spanx style="verb">instancePath</spanx>
pointing to <spanx style="emph">I</spanx>, and a <spanx style="verb">schemaPath</spanx> pointing to <spanx style="emph">M</spanx>.</t>
<t>If the instance is a JSON object, <spanx style="emph">I</spanx> exists, and <spanx style="emph">S</spanx> exists, then the
instance must satisfy <spanx style="emph">S</spanx>’s value. By <xref target="syntax"/>, <spanx style="emph">S</spanx>’s value must be a schema
of the properties form. Apply the “discriminator tag exemption” afforded in
<xref target="semantics-form-props"/> to <spanx style="emph">I</spanx> when evaluating whether the instance satisfies
<spanx style="emph">S</spanx>’s value. <vspace blankLines='1'/>
Otherwise, the error indicators for this case shall be error indicators from
evaluating <spanx style="emph">S</spanx>’s value against the instance, with the “discriminator tag
exemption” applied to <spanx style="emph">I</spanx>.</t>
</list></t>
<t>The list items above are defined in a mutually exclusive way. For any given
instance and schema, exactly one of the list items above will apply.</t>
<t>For example, the schema:</t>
<figure><artwork type="json"><![CDATA[
{
"discriminator": "version",
"mapping": {
"v1": {
"properties": {
"a": { "type": "float32" }
}
},
"v2": {
"properties": {
"a": { "type": "string" }
}
}
}
}
]]></artwork></figure>
<t>rejects</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/discriminator" }]
]]></artwork></figure>
<t>(This is the case of the instance not being an object.)</t>
<t>Also rejected is</t>
<figure><artwork type="json"><![CDATA[
{}
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/discriminator" }]
]]></artwork></figure>
<t>(This is the case of <spanx style="emph">I</spanx> not existing.)</t>
<t>Also rejected is</t>
<figure><artwork type="json"><![CDATA[
{ "version": 1 }
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[
{
"instancePath": "/version",
"schemaPath": "/discriminator"
}
]
]]></artwork></figure>
<t>(This is the case of <spanx style="emph">I</spanx> existing, but not having a string value.)</t>
<t>Also rejected is</t>
<figure><artwork type="json"><![CDATA[
{ "version": "v3" }
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[
{
"instancePath": "/version",
"schemaPath": "/mapping"
}
]
]]></artwork></figure>
<t>(This is the case of <spanx style="emph">I</spanx> existing and having a string value, but <spanx style="emph">S</spanx> not
existing.)</t>
<t>Also rejected is</t>
<figure><artwork type="json"><![CDATA[
{ "version": "v2", "a": 3 }
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[
{
"instancePath": "/a",
"schemaPath": "/mapping/v2/properties/a/type"
}
]
]]></artwork></figure>
<t>(This is the case of <spanx style="emph">I</spanx> and <spanx style="emph">S</spanx> existing, but the instance not satisfying <spanx style="emph">S</spanx>’s
value.)</t>
<t>Finally, the schema accepts</t>
<figure><artwork type="json"><![CDATA[
{ "version": "v2", "a": "foo" }
]]></artwork></figure>
<t>This instance is accepted even though <spanx style="verb">version</spanx> is not mentioned by
<spanx style="verb">/mapping/v2/properties</spanx>; the “discriminator tag exemption” ensures that
<spanx style="verb">version</spanx> is not treated as an additional property when evaluating the instance
against <spanx style="emph">S</spanx>’s value.</t>
<t>By contrast, consider the same schema, but with <spanx style="verb">nullable</spanx> being <spanx style="verb">true</spanx>. The
schema:</t>
<figure><artwork type="json"><![CDATA[
{
"nullable": true,
"discriminator": "version",
"mapping": {
"v1": {
"properties": {
"a": { "type": "float32" }
}
},
"v2": {
"properties": {
"a": { "type": "string" }
}
}
}
}
]]></artwork></figure>
<t>accepts</t>
<figure><artwork type="json"><![CDATA[
null
]]></artwork></figure>
<t>To further illustrate the discriminator form with examples, recall the JTD
schema in <xref target="syntax-form-discriminator"/>, reproduced here:</t>
<figure><artwork type="json"><![CDATA[
{
"discriminator": "event_type",
"mapping": {
"account_deleted": {
"properties": {
"account_id": { "type": "string" }
}
},
"account_payment_plan_changed": {
"properties": {
"account_id": { "type": "string" },
"payment_plan": { "enum": ["FREE", "PAID"] }
},
"optionalProperties": {
"upgraded_by": { "type": "string" }
}
}
}
}
]]></artwork></figure>
<t>This schema accepts</t>
<figure><artwork type="json"><![CDATA[
{ "event_type": "account_deleted", "account_id": "abc-123" }
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{
"event_type": "account_payment_plan_changed",
"account_id": "abc-123",
"payment_plan": "PAID"
}
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{
"event_type": "account_payment_plan_changed",
"account_id": "abc-123",
"payment_plan": "PAID",
"upgraded_by": "users/mkhwarizmi"
}
]]></artwork></figure>
<t>but rejects</t>
<figure><artwork type="json"><![CDATA[
{}
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[{ "instancePath": "", "schemaPath": "/discriminator" }]
]]></artwork></figure>
<t>and rejects</t>
<figure><artwork type="json"><![CDATA[
{ "event_type": "some_other_event_type" }
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[
{
"instancePath": "/event_type",
"schemaPath": "/mapping"
}
]
]]></artwork></figure>
<t>and rejects</t>
<figure><artwork type="json"><![CDATA[
{ "event_type": "account_deleted" }
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[{
"instancePath": "",
"schemaPath": "/mapping/account_deleted/properties/account_id"
}]
]]></artwork></figure>
<t>and rejects</t>
<figure><artwork type="json"><![CDATA[
{
"event_type": "account_payment_plan_changed",
"account_id": "abc-123",
"payment_plan": "PAID",
"xxx": "asdf"
}
]]></artwork></figure>
<t>with the error indicator</t>
<figure><artwork type="json"><![CDATA[
[{
"instancePath": "/xxx",
"schemaPath": "/mapping/account_payment_plan_changed"
}]
]]></artwork></figure>
</section>
</section>
</section>
<section anchor="iana-considerations" title="IANA Considerations">
<t>No IANA considerations.</t>
</section>
<section anchor="security-considerations" title="Security Considerations">
<t>Implementations of JTD will necessarily be manipulating JSON data. Therefore,
the security considerations of <xref target="RFC8259"/> are all relevant here.</t>
<t>Implementations which evaluate user-inputted schemas SHOULD implement mechanisms
to detect, and abort, circular references which might cause a naive
implementation to go into an infinite loop. Without such mechanisms,
implementations may be vulnerable to denial-of-service attacks.</t>
</section>
</middle>
<back>
<references title='Normative References'>
&RFC3339;
&RFC4287;
&RFC6901;
&RFC8259;
&RFC8610;
&RFC2119;
&RFC8174;
</references>
<references title='Informative References'>
&RFC7071;
&RFC7493;
&I-D.handrews-json-schema;
<reference anchor="OPENAPI" target="https://spec.openapis.org/oas/v3.0.2">
<front>
<title>OpenAPI Specification</title>
<author >
<organization>OpenAPI Initiative</organization>
</author>
<date year="2019" month="October" day="08"/>
</front>
</reference>
</references>
<section anchor="other-considerations" title="Rationale for Omitted Features">
<t>This appendix is not normative.</t>
<t>This section describes possible features which are intentionally left out of
JSON Type Definition, and justifies why these features are omitted.</t>
<section anchor="other-considerations-int64" title="Support for 64-bit Numbers">
<t>This document does not allow <spanx style="verb">int64</spanx> or <spanx style="verb">uint64</spanx> as values for the JTD <spanx style="verb">type</spanx>
keyword (see <xref target="syntax-form-type"/> and <xref target="semantics-form-type"/>). Such
hypothetical <spanx style="verb">int64</spanx> or <spanx style="verb">uint64</spanx> types would behave like <spanx style="verb">int32</spanx> or <spanx style="verb">uint32</spanx>
(respectively), but with the range of values associated with 64-bit instead of
32-bit integers, that is:</t>
<t><list style="symbols">
<t><spanx style="verb">int64</spanx> would accept numbers between -(2**63) and (2**63)-1</t>
<t><spanx style="verb">uint64</spanx> would accept numbers between 0 and (2**64)-1</t>
</list></t>
<t>Users of <spanx style="verb">int64</spanx> and <spanx style="verb">uint64</spanx> would likely expect that the full range of signed
or unsigned 64-bit integers could interoperably be transmitted as JSON without
loss of precision. But this assumption is likely to be incorrect, for the
reasons given in Section 2.2 of <xref target="RFC7493"/>.</t>
<t><spanx style="verb">int64</spanx> and <spanx style="verb">uint64</spanx> likely would have led users to falsely assume that the full
range of 64-bit integers can be interoperably processed as JSON without loss of
precision. To avoid leading users astray, JTD omits <spanx style="verb">int64</spanx> and <spanx style="verb">uint64</spanx>.</t>
</section>
<section anchor="support-for-non-root-definitions" title="Support for Non-Root Definitions">
<t>This document disallows the <spanx style="verb">definitions</spanx> keyword from appearing outside of root
schemas (see <xref target="cddl-schema"/>). Conceivably, this document could have instead
allowed <spanx style="verb">definitions</spanx> to appear on any schema, even non-root ones. Under this
alternative design, <spanx style="verb">ref</spanx>s would resolve to a definition in the “nearest” (i.e.,
most nested) schema which both contained the <spanx style="verb">ref</spanx> and which had a
suitably-named <spanx style="verb">definitions</spanx> member.</t>
<t>For instance, under this alternative approach, one could define schemas like the
one in <xref target="hypothetical-ref"/>:</t>
<figure title="A hypothetical schema had this document permitted
non-root definitions. This is not a correct JTD schema." anchor="hypothetical-ref"><artwork type="json"><![CDATA[
{
"properties": {
"foo": {
"definitions": {
"user": { "properties": { "user_id": {"type": "string" }}}
},
"ref": "user"
},
"bar": {
"definitions": {
"user": { "properties": { "user_id": {"type": "string" }}}
},
"ref": "user"
},
"baz": {
"definitions": {
"user": { "properties": { "userId": {"type": "string" }}}
},
"ref": "user"
}
}
}
]]></artwork></figure>
<t>If schemas like that in <xref target="hypothetical-ref"/> were permitted, code generation
from JTD schemas would be more difficult, and the generated code would be less
useful.</t>
<t>Code generation would be more difficult because it would force code generators
to implement a name mangling scheme for types generated from definitions. This
additional difficulty is not immense, but adds complexity to an otherwise
relatively trivial task.</t>
<t>Generated code would be less useful because generated, mangled struct names are
less pithy than human-defined struct names. For instance, the <spanx style="verb">user</spanx> definitions
in <xref target="hypothetical-ref"/> might have been generated into types named
<spanx style="verb">PropertiesFooUser</spanx>, <spanx style="verb">PropertiesBarUser</spanx>, and <spanx style="verb">PropertiesBazUser</spanx>; obtuse names
like these are less useful to human-written code than names like <spanx style="verb">User</spanx>.</t>
<t>Furthermore, even though <spanx style="verb">PropertiesFooUser</spanx> and <spanx style="verb">PropertiesBarUser</spanx> would be
essentially identical, they would not be interchangeable in many
statically-typed programming languages. A code generator could attempt to
circumvent this by deduplicating identical definitions, but then the user might
be confused as to why the subtly distinct <spanx style="verb">PropertiesBazUser</spanx>, defined from a
schema allowing a property named <spanx style="verb">userId</spanx> (not <spanx style="verb">user_id</spanx>), was not deduplicated.</t>
<t>Because there seem to be implementation and usability challenges associated with
non-root definitions, and because it would be easier to later amend JTD to
permit for non-root definitions than to later amend JTD to prohibit them, this
document does not permit non-root definitions in JTD schemas.</t>
</section>
</section>
<section anchor="comparison-with-cddl" title="Comparison with CDDL">
<t>This appendix is not normative.</t>
<t>To aid the reader familiar with CDDL, this section illustrates how JTD works by
presenting JTD schemas and CDDL schemas which accept and reject the same
instances.</t>
<t>The JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = any
]]></artwork></figure>
<t>The JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{
"definitions": {
"a": { "elements": { "ref": "b" }},
"b": { "type": "float32" }
},
"elements": {
"ref": "a"
}
}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = [* a]
a = [* b]
b = number
]]></artwork></figure>
<t>The JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{ "enum": ["PENDING", "DONE", "CANCELED"]}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = "PENDING" / "DONE" / "CANCELED"
]]></artwork></figure>
<t>The JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{"type": "boolean"}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = bool
]]></artwork></figure>
<t>The JTD schemas:</t>
<figure><artwork type="json"><![CDATA[
{"type": "float32"}
]]></artwork></figure>
<t>and</t>
<figure><artwork type="json"><![CDATA[
{"type": "float64"}
]]></artwork></figure>
<t>both accept the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = number
]]></artwork></figure>
<t>The JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{"type": "string"}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = tstr
]]></artwork></figure>
<t>The JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{"type": "timestamp"}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = tdate
]]></artwork></figure>
<t>The JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{ "elements": { "type": "float32" }}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = [* number]
]]></artwork></figure>
<t>The JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{
"properties": {
"a": { "type": "boolean" },
"b": { "type": "float32" }
},
"optionalProperties": {
"c": { "type": "string" },
"d": { "type": "timestamp" }
}
}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = { a: bool, b: number, ? c: tstr, ? d: tdate }
]]></artwork></figure>
<t>The JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{ "values": { "type": "float32" }}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = { * tstr => number }
]]></artwork></figure>
<t>Finally, the JTD schema:</t>
<figure><artwork type="json"><![CDATA[
{
"discriminator": "a",
"mapping": {
"foo": {
"properties": {
"b": { "type": "float32" }
}
},
"bar": {
"properties": {
"b": { "type": "string" }
}
}
}
}
]]></artwork></figure>
<t>accepts the same instances as the CDDL rule:</t>
<figure><artwork type="cddl"><![CDATA[
root = { a: "foo", b: number } / { a: "bar", b: tstr }
]]></artwork></figure>
</section>
<section anchor="examples" title="Example">
<t>This appendix is not normative.</t>
<t>As a demonstration of JTD, in <xref target="JTD-reputation-object"/> is a JTD schema
closely equivalent to the plain-English definition <spanx style="verb">reputation-object</spanx> described
in Section 6.2.2 of <xref target="RFC7071"/>:</t>
<figure title="A JTD schema describing &quot;reputation-object&quot;
from Section 6.6.2 of [RFC7071]" anchor="JTD-reputation-object"><artwork type="json"><![CDATA[
{
"properties": {
"application": { "type": "string" },
"reputons": {
"elements": {
"additionalProperties": true,
"properties": {
"rater": { "type": "string" },
"assertion": { "type": "string" },
"rated": { "type": "string" },
"rating": { "type": "float32" },
},
"optionalProperties": {
"confidence": { "type": "float32" },
"normal-rating": { "type": "float32" },
"sample-size": { "type": "float64" },
"generated": { "type": "float64" },
"expires": { "type": "float64" }
}
}
}
}
}
]]></artwork></figure>
<t>This schema does not enforce the requirement that <spanx style="verb">sample-size</spanx>, <spanx style="verb">generated</spanx>,
and <spanx style="verb">expires</spanx> be unbounded positive integers. It does not express the limitation
that <spanx style="verb">rating</spanx>, <spanx style="verb">confidence</spanx>, and <spanx style="verb">normal-rating</spanx> should not have more than three
decimal places of precision.</t>
<t>The example in <xref target="JTD-reputation-object"/> can be compared against the equivalent
example in Appendix H of <xref target="RFC8610"/>.</t>
</section>
<section numbered="no" anchor="acknowledgments" title="Acknowledgments">
<t>Carsten Bormann provided lots of useful guidance and feedback on JTD’s design
and the structure of this document.</t>
<t>Evgeny Poberezkin suggested the addition of <spanx style="verb">nullable</spanx>, and thoroughly vetted
this document for mistakes and opportunities for simplification.</t>
<t>Tim Bray suggested the current <spanx style="verb">ref</spanx> model, and the addition of <spanx style="verb">enum</spanx>. Anders
Rundgren suggested extending <spanx style="verb">type</spanx> to have more support for numerical types.
James Manger suggested additional clarifying examples of how integer types work.
Adrian Farrel suggested many improvements to help make this document clearer.</t>
<t>Members of the IETF JSON mailing list – in particular, Pete Cordell, Phillip
Hallam-Baker, Nico Williams, John Cowan, Rob Sayre, and Erik Wilde – provided
lots of useful feedback.</t>
<t>OpenAPI’s <spanx style="verb">discriminator</spanx> object <xref target="OPENAPI"/> inspired the <spanx style="verb">discriminator</spanx> form.
<xref target="I-D.handrews-json-schema"/> influenced various parts of JTD’s early design.</t>
</section>
</back>
<!-- ##markdown-source:
H4sIAFA+/l4AA+1923YbR5Lge35FLvRgiQ1AIiVLMrWeXlqiu+m1Ja0kT59Z
20csAEmiWkAVpi6kYDXnW/Zb9ss2bnmrCwBSbHePd3xOt0CgKjMyMjLuETka
jVSVVgtzqL97++qlfrdeGf3CnKVZWqV5pmb5NEuW8OusSM6qUT1NCvh69NcS
/q+CZ0cz9+zowSM1Syp49uDBwYPRg8ejg6cqXRWHuirqsjp48OCrBwcqKUxy
qI9Wq0U6TfC1Ul2eH+qTbGZWBv4vq/TberJMyxKn/3CJP1WmyEw1eoEgKHjr
UJuPK6VW6aHSusqnh3ptSvhY5kVVmLMSvy7XS/pIP6mkruZ5gd+PdJrBtz+O
9XNaCnylNS/xx8W6LE34fV4AaG/N+RLAGqf5EGCZ0g/JZFKYC/cbfVfC3AZg
23/wAMZYpGd5kaWJfktf0xPTtFrDO0mmvy2SbJqW05y/z2cw/VeP9vf35e86
qwp49EfArJnBEIDWUudn+mhpCsAbPWWWSbo41DVB/T9KgXKaL5XK8mIJyL0w
uOI33z5/+PDhV/Lx0cHTJ/Lx8VcP9uXj04Mv7QNPH+8/OFRpdtYY48mDJ/bp
J4++eogfT0YvxvMkmxXmsmSSKKdzAAt/e/X6+OXR65NDArVKinNEzbyqVuXh
/fvlykzHOex3skrLMWD5fp6U9y8ejh+MD/gFJslX8AgMot/C8+mZEAxvgNtQ
t0/24RMkR4KcfrUkuf/VaB+o8qlSo9EINhC2K5lWSr2bp6UGMq8RfXpV5Ku8
BGQnmhEw1NNksYBN6Doe+u53717cG+KjambKaZFO0uxcV3Ojy3kCj8KWfZdc
JG/hl1WlX03+aqaVfplXibwNY97TS1OWybkpx/qkKjXsaqbO82QBMBQGyFsD
miYLQ1Siz01mCn77rMiXmhEOj5b60iwW+O8KTgG9cAFEOGOUXabVHAgU9iop
ZumvsBxTFHkBZ2GGWM0LmPxdDoADLuAUDjWsS8PnFM5ehiMADtZ6kS6JHqtc
TYzOcr3MAUI4iwWsAPAN7wNt4+qRNcARLCuzJLrFReH5SJaI4fMiWS4RUYsk
O69p6bwNwXQ8GUE/DFeHo8+AGpA9IHKWyQdD0FpMAGSIVmW3tBzSM/Bmni9w
UljuijYGXjJJmZoCx5nU6WI2bpLDLIcXs7zS8wSWd3L87lvYhqw0WVkDzrMZ
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
hc0EAiAAm+iIpEM0Vv8PkzDhsur1AAA=
-->
</rfc>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment