From aa07af6ed8a421a492aa5369d91ced5da909d812 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 6 Oct 2025 15:51:33 -0400 Subject: [PATCH] Fully document JSON Schema Draft 7 Signed-off-by: Juan Cruz Viotti --- content/draft7/core/comment.markdown | 53 +++++ content/draft7/core/id.markdown | 167 ++++++++++++++ content/draft7/core/ref.markdown | 209 ++++++++++++++++++ content/draft7/core/schema.markdown | 131 +++++++++++ .../validation/additionalItems.markdown | 97 ++++++++ .../validation/additionalProperties.markdown | 10 +- content/draft7/validation/allOf.markdown | 23 +- content/draft7/validation/anyOf.markdown | 108 +++++++++ content/draft7/validation/const.markdown | 60 +++++ content/draft7/validation/contains.markdown | 42 ++++ .../validation/contentEncoding.markdown | 87 ++++++++ .../validation/contentMediaType.markdown | 83 +++++++ content/draft7/validation/default.markdown | 88 ++++++++ .../draft7/validation/definitions.markdown | 58 +++++ .../draft7/validation/dependencies.markdown | 202 +++++++++++++++++ .../draft7/validation/description.markdown | 69 ++++++ content/draft7/validation/else.markdown | 61 +++++ content/draft7/validation/enum.markdown | 79 +++++++ content/draft7/validation/examples.markdown | 54 +++++ .../validation/exclusiveMaximum.markdown | 73 ++++++ .../validation/exclusiveMinimum.markdown | 73 ++++++ content/draft7/validation/format.markdown | 76 +++++++ content/draft7/validation/if.markdown | 136 ++++++++++++ content/draft7/validation/items.markdown | 104 +++++++++ content/draft7/validation/maxItems.markdown | 38 ++++ content/draft7/validation/maxLength.markdown | 53 +++++ .../draft7/validation/maxProperties.markdown | 38 ++++ content/draft7/validation/maximum.markdown | 73 ++++++ content/draft7/validation/minItems.markdown | 34 +++ content/draft7/validation/minLength.markdown | 42 ++++ .../draft7/validation/minProperties.markdown | 34 +++ content/draft7/validation/minimum.markdown | 73 ++++++ content/draft7/validation/multipleOf.markdown | 107 +++++++++ content/draft7/validation/not.markdown | 55 +++++ content/draft7/validation/oneOf.markdown | 125 +++++++++++ content/draft7/validation/pattern.markdown | 51 +++++ .../validation/patternProperties.markdown | 132 +++++++++++ content/draft7/validation/properties.markdown | 96 ++++++++ .../draft7/validation/propertyNames.markdown | 91 ++++++++ content/draft7/validation/readOnly.markdown | 84 +++++++ content/draft7/validation/required.markdown | 76 +++++++ content/draft7/validation/then.markdown | 61 +++++ content/draft7/validation/title.markdown | 63 ++++++ content/draft7/validation/type.markdown | 117 ++++++++++ .../draft7/validation/uniqueItems.markdown | 61 +++++ content/draft7/validation/writeOnly.markdown | 87 ++++++++ 46 files changed, 3715 insertions(+), 19 deletions(-) diff --git a/content/draft7/core/comment.markdown b/content/draft7/core/comment.markdown index 5add4280..3c0e9471 100644 --- a/content/draft7/core/comment.markdown +++ b/content/draft7/core/comment.markdown @@ -10,3 +10,56 @@ metaschema: "http://json-schema.org/draft-07/schema#" introduced_in: draft7 index: -9 --- + +The [`$comment`]({{< ref "draft7/core/comment" >}}) keyword is a +standardised placeholder for explanatory string schema comments. This +keyword is completely ignored by the evaluation process and it is possible +to strip instances of this keyword when distributing your schemas for the +purpose of space-efficiency. This keyword is commonly used to declare [TODO +comments](https://en.wikipedia.org/wiki/Comment_%28computer_programming%29#Tags) +in various parts of a schema. + +{{}} + +Compared to other similar keywords such as [`title`]({{< ref +"draft7/validation/title" >}}) and [`description`]({{< ref +"draft7/validation/description" >}}), this keyword does not produce any +semantic meaning. Furthermore, the specification explicitly prohibits any JSON +Schema tooling from inferring meaning from this keyword or elevating its +contents to the end user in any way. + +{{}} + +{{}} + +The JSON data format does not support any form of comments at the grammar +level. While this is a common point of contention, comment support (or any +other improvement) will be never added. The [ECMA +404](https://ecma-international.org/publications-and-standards/standards/ecma-404/) +JSON standard declares that: *"it is not expected that the JSON grammar will +ever change"*. If this keyword is not enough, there are various other data +formats that operate on the JSON data model that have comment support, like +[YAML](https://yaml.org) and [JSON5](https://json5.org). However, JSON remains +by far the preferred data format within the community, both when authoring +schemas and over the wire. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$comment": "This is an internal note about the schema that is ignored by the evaluation process", + "properties": { + "name": { + "$comment": "TODO: Add `pattern` to better validate names", + "type": "string" + } + } +} +{{}} + +{{}} +{ "name": "John Doe" } +{{}} diff --git a/content/draft7/core/id.markdown b/content/draft7/core/id.markdown index e4d79d53..a708859d 100644 --- a/content/draft7/core/id.markdown +++ b/content/draft7/core/id.markdown @@ -18,3 +18,170 @@ related: - vocabulary: core keyword: $schema --- + +The [`$id`]({{< ref "draft7/core/id" >}}) keyword explicitly turns a schema +into a _schema resource_ (a schema that is associated with a URI). Relative +URIs are resolved against the _current_ base URI, which is either the closest +parent [`$id`]({{< ref "draft7/core/id" >}}) keyword (applicable in the case +of compound schemas), or the base URI as determined by the context on which the +schema is declared (i.e. serving a schema over HTTP _may_ implicitly award it +such URL as the base). + +{{}} + +This keyword directly applies (without modifications or extensions) the concept +of URIs to schemas. **If you are having a hard time following the concepts +discussed in this page, it is probably because you don't have a strong grasp of +URIs yet** (a notably hard but universal pre-requisite!). + +To learn more about URIs, we strongly suggest studying the [IETF RFC +3986](https://www.rfc-editor.org/info/rfc3986) URI standard. To avoid +confusion, note that there is also a [WHATWG URL +Standard](https://url.spec.whatwg.org) that targets URLs in the context of web +browsers. However, JSON Schema only implements and expects the IETF original +standard. + +{{}} + +{{}} + +In JSON Schema, schema identifiers are merely identifiers and no behaviour is +imposed on them. In particular, JSON Schema does not guarantee that a schema +with an HTTP URL identifier is actually resolvable at such URL. To avoid +surprises, JSON Schema implementations must be careful with automatically +sending remote network requests when encountering supposely resolvable schema +identifiers. + +{{}} + +{{}} + +It is strongly recommended for every schema file to explicitly declare an +_absolute_ URI using this keyword. By doing so, you completely avoid various +complex URI resolution edge cases, mainly when the base URI is implicit and +context-dependent. + +If you are serving schemas over the network (i.e. over HTTP), it is common to +set this keyword to the target URL. However, if your schemas are not accessible +over the network, prefer using a +[URN](https://en.wikipedia.org/wiki/Uniform_Resource_Name) (with a valid +namespace registered by +[IANA](https://www.iana.org/assignments/urn-namespaces/urn-namespaces.xhtml)) +or a non-locatable URI scheme such as a [Tag URI](https://www.taguri.org). + +{{}} + +To debug the role of the [`$id`]({{< ref "draft7/core/id" >}}) keyword on +a schema (particularly schemas with embedded resources), try the [`jsonschema +inspect`](https://github.com/sourcemeta/jsonschema/blob/main/docs/inspect.markdown) +command. This command prints detailed information about each schema resource, +subschema, location, and reference present in the schema. For example: + +```sh +$ jsonschema inspect schema.json +(RESOURCE) URI: https://example.com/schema + Type : Static + Root : https://example.com/schema + Pointer : + Base : https://example.com/schema + Relative Pointer : + Dialect : http://json-schema.org/draft-07/schema# + Base Dialect : http://json-schema.org/draft-07/schema# + Parent : + Instance Location : + +... + +(SUBSCHEMA) URI: https://example.com/schema#/properties/foo + Type : Static + Root : https://example.com/schema + Pointer : /properties/foo + Base : https://example.com/schema + Relative Pointer : /properties/foo + Dialect : http://json-schema.org/draft-07/schema# + Base Dialect : http://json-schema.org/draft-07/schema# + Parent : + Instance Location : /foo + +... + +(REFERENCE) ORIGIN: /$schema + Type : Static + Destination : http://json-schema.org/draft-07/schema + - (w/o fragment) : http://json-schema.org/draft-07/schema + - (fragment) : +``` + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://example.com/schemas/even-number.json", + "type": "number", + "multipleOf": 2 +} +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "tag:example.com,2025:even-number", + "type": "number", + "multipleOf": 2 +} +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "urn:example:even-number", + "type": "number", + "multipleOf": 2 +} +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://example.com/schemas/user.json", + "type": "object", + "properties": { + "name": { "$ref": "#nonEmptyString" }, + "email": { "$ref": "#nonEmptyString" } + }, + "definitions": { + "nonEmptyString": { + "$id": "#nonEmptyString", + "type": "string", + "minLength": 1 + } + } +} +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$comment": "This is the root schema resource", + "$id": "https://example.com/schemas/root.json", + "properties": { + "foo": { + "$comment": "The resolved URI of this nested schema resource is https://example.com/schemas/foo.json", + "$id": "foo.json" + }, + "bar": { + "$comment": "The resolved URI of this nested schema resource is https://example.com/schemas/bar.json", + "$id": "/schemas/bar.json" + }, + "baz": { + "$comment": "The resolved URI of this nested schema resource is https://absolute.example/baz.json", + "$id": "https://absolute.example/baz.json", + "items": { + "$comment": "The resolved URI of this nested schema resource is https://absolute.example/deep", + "$id": "deep" + } + } + } +} +{{}} diff --git a/content/draft7/core/ref.markdown b/content/draft7/core/ref.markdown index 24295a41..c53fdf79 100644 --- a/content/draft7/core/ref.markdown +++ b/content/draft7/core/ref.markdown @@ -24,3 +24,212 @@ related: - vocabulary: validation keyword: definitions --- + +The [`$ref`]({{< ref "draft7/core/ref" >}}) keyword enables a schema to +reference another schema by its URI, effectively importing its keywords into the +current evaluation process. This keyword is the cornerstone of schema +composition, allowing complex schemas to be created out of simpler ones. A +reference may set its URI fragment to a [JSON +Pointer](https://www.rfc-editor.org/rfc/rfc6901) that determines the destination +of the reference after first resolving the rest of the URI. + +{{}} + +In JSON Schema [Draft 7](/draft7) and earlier versions, **any subschema +declaring the [`$ref`]({{< ref "draft7/core/ref" >}}) keyword is considered to +be a _reference object_ and any other sibling keyword is silently ignored**. As +a consequence, subschemas with references that make use of other keywords must +artificially wrap the reference into its own subschema using keywords like +[`allOf`]({{< ref "draft7/validation/allof" >}}). + +{{}} + +{{}} + +**Avoid referencing other schema files using their file paths**. While some +implementations support this by automatically constructing schema URIs that +make use of the `file://` scheme, this is not enforced behaviour. The only +standard and guaranteed mechanism of declaring a schema URI for identification +and referencing purposes is through the [`$id`]({{< ref "draft7/core/id" >}}) keyword. + +{{}} + +{{}} + +The target of a reference must be a schema. Referencing a JSON value that is +not unambiguously recognised as a schema leads to undefined behaviour. This +not only includes referencing arbitrary JSON files (the obvious case), but +also referencing parts of a schema that a JSON Schema evaluator does not +consider to be a subschema. For example, referencing the contents of the +[`examples`]({{< ref "draft7/validation/examples" >}}) keyword. + +{{}} + +References are either _internal_ (pointing at schemas within the same schema +definition) or _external_ (pointing at schema resources outside the given schema +definition). If the reference is a relative URI, it is resolved against the +_current_ base URI, which is either the closest parent URI as set by the +[`$id`]({{< ref "draft7/core/id" >}}) keyword, or the base URI as determined by +the context on which the schema is declared. Schema wrappers like OpenAPI are +notable examples of the latter. A relative reference from a schema embedded in +an OpenAPI specification is resolved from the root of the API specification, and +not from the root of the schema. + +{{}} + +It is highly recommended to make use of _external_ references to break down +complex monolithic schemas into smaller schema files. However, for performance +and integrity reasons, avoid resolving these external schemas (i.e. over HTTP +or the filesystem) at runtime. + +You can automatically inline external references at build time using the +[`jsonschema +bundle`](https://github.com/sourcemeta/jsonschema/blob/main/docs/bundle.markdown) +command. + +{{}} + +Note that a reference to an absolute URI does not necessarily mean that the +reference is external. Conversely, a reference to a relative URI does not +necessarily mean that the reference is internal. When encountering any type +of reference, a JSON Schema implementation will check if the root schema +resource or its nested schema resources (if any) declare the canonically +resolved version of such URI through the [`$id`]({{< ref "draft7/core/id" +>}}) keyword. If so, the reference is considered internal. This +internal-first lookup is what enables the standard +[bundling](https://json-schema.org/blog/posts/bundling-json-schema-compound-documents) +process. + +{{}} + +If you are having a hard time understanding references and some of its more +subtle scenarios (like base URI resolution), it is probably because you don't +have a strong grasp of URIs yet (a notably hard but universal +pre-requisite!). + +To learn more about URIs, we strongly suggest studying the [IETF RFC +3986](https://www.rfc-editor.org/info/rfc3986) URI standard. To avoid +confusion, note that there is also a [WHATWG URL +Standard](https://url.spec.whatwg.org) that targets URLs in the context of +web browsers. However, JSON Schema only implements and expects the IETF +original standard. As a notable extension, this keyword supports referencing +specific parts of a schema through the use of a JSON Pointer, so we also +recommend studying the [IETF RFC 6901](https://www.rfc-editor.org/info/rfc6901) +JSON Pointer standard and its [URI fragment identifier +representation](https://www.rfc-editor.org/rfc/rfc6901#section-6). + +{{}} + +To debug references and how JSON Schema is interpreting your relative URIs, +try the [`jsonschema +inspect`](https://github.com/sourcemeta/jsonschema/blob/main/docs/inspect.markdown) +command. This command prints detailed information about each schema reference +and of each location of the schema. For example: + +```sh +$ jsonschema inspect schema.json +... + +(REFERENCE) ORIGIN: /properties/foo/$ref + Type : Static + Destination : https://example.com/schemas/example#/definitions/uuid + - (w/o fragment) : https://example.com/schemas/example + - (fragment) : /definitions/uuid + +... +``` + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "foo": { + "type": "string", + "$comment": "WARNING! This reference overrides the sibling `type` keyword!", + "$ref": "#/definitions/test" + } + }, + "definitions": { + "test": { "minLength": 2 } + } +} +{{}} + +{{}} +12345 +{{}} + +{{}} +"foo" +{{}} + +{{}} +"x" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://example.com/my-schema", + "properties": { + "byRelativeFragmentPointer": { + "$ref": "#/definitions/helper" + }, + "byAbsoluteFragmentPointer": { + "$ref": "https://example.com/my-schema#/definitions/helper" + }, + "byRelativeURI": { + "$ref": "my-helper" + }, + "byRelativeRootPathURI": { + "$ref": "/my-helper" + }, + "byRelativeBackslashURI": { + "$ref": "my-schema/../my-helper" + }, + "byAbsoluteURI": { + "$ref": "https://example.com/my-helper" + } + }, + "definitions": { + "helper": { + "$id": "my-helper", + "type": "string" + } + } +} +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://example.com/my-schema", + "properties": { + "byAbsoluteURI": { + "$ref": "https://example.com/my-other-schema" + }, + "byRelativeURI": { + "$ref": "my-other-schema" + }, + "byRelativeRootPathURI": { + "$ref": "/my-other-schema" + }, + "byRelativeBackslashURI": { + "$ref": "my-schema/../my-other-schema" + } + } +} +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "byAbsoluteURI": { + "$ref": "urn:example:my-other-schema" + } + } +} +{{}} diff --git a/content/draft7/core/schema.markdown b/content/draft7/core/schema.markdown index 106d3e64..1cbe1f4b 100644 --- a/content/draft7/core/schema.markdown +++ b/content/draft7/core/schema.markdown @@ -17,3 +17,134 @@ related: - vocabulary: validation keyword: definitions --- + +The [`$schema`]({{< ref "draft7/core/schema" >}}) keyword serves to explicitly +associate a _schema resource_ with the JSON Schema dialect that defines it, +where the dialect is the identifier of a meta-schema that defines the keywords +in use and imposes syntactic constraints on its schema instances. If the +[`$schema`]({{< ref "draft7/core/schema" >}}) keyword is not declared, the +schema inherits its context-specific or implementation-specific default +dialect. + +{{}} It is common to avoid the [`$schema`]({{< ref "draft7/core/schema" >}}) keyword when working with +[OpenAPI](https://www.openapis.org). This is possible because the OpenAPI +specification clearly documents what the default JSON Schema dialect is for +every version. For example, [OpenAPI +v3.1.1](https://spec.openapis.org/oas/latest.html#json-schema-keywords) defines +the default dialect as `https://spec.openapis.org/oas/3.1/dialect/base`. +{{}} + +Strictly-compliant JSON Schema implementations will refuse to process a schema +whose dialect cannot be unambiguously determined. + +{{}} To avoid undefined behavior, it is generally recommended to +always explicitly set the dialect of a schema using the [`$schema`]({{< ref "draft7/core/schema" >}}) keyword. This ensures that less strict +implementations unambiguously know how to process the schema and don't attempt +to guess.{{}} + +Note that the [`$schema`]({{< ref "draft7/core/schema" >}}) keyword can occur +multiple times in the same schema, and not only at the top-level. This is often +the case when performing [JSON Schema +Bundling](https://github.com/sourcemeta/jsonschema/blob/main/docs/bundle.markdown) +to inline externally referenced schemas that might be based on different +dialects of JSON Schema. + +{{}}JSON Schema prohibits referencing meta-schemas using +relative URIs. The fundamental reason for this is that resolving the +meta-schema is necessary for correctly determining the base URI of the schema, +from which a relative meta-schema reference would be resolved, introducing a +circular problem. + +A common occurrence of this issue is setting the [`$schema`]({{< ref "draft7/core/schema" >}}) keyword to a relative path, which is again invalid +according to the specification.{{}} + +{{}}JSON Schema prohibits the use of the this keyword on +arbitrary subschemas that do not represent schema resources. It can only be +present at the root of the schema (an implicit schema resource) or as a sibling +of the [`$id`]({{< ref "draft7/core/id" >}}) keyword (an explicit schema +resource).{{}} + +A schema is considered syntactic valid if it successfully validates against its +dialect meta-schema. You can validate a schema against its meta-schema using +the [`jsonschema +metaschema`](https://github.com/sourcemeta/jsonschema/blob/main/docs/metaschema.markdown) +command. For example: + +```sh +$ jsonschema metaschema my-schema.json +``` + +To debug the role of the [`$schema`]({{< ref "draft7/core/schema" >}}) +keyword on a schema (particularly schemas with embedded resources), try the +[`jsonschema +inspect`](https://github.com/sourcemeta/jsonschema/blob/main/docs/inspect.markdown) +command. This command prints detailed information about each schema resource, +subschema, location, and reference present in the schema. For example: + +```sh +$ jsonschema inspect schema.json +(RESOURCE) URI: https://example.com/schema + Type : Static + Root : https://example.com/schema + Pointer : + Base : https://example.com/schema + Relative Pointer : + Dialect : http://json-schema.org/draft-07/schema# + Base Dialect : http://json-schema.org/draft-07/schema# + Parent : + Instance Location : + +... + +(SUBSCHEMA) URI: https://example.com/schema#/properties/foo + Type : Static + Root : https://example.com/schema + Pointer : /properties/foo + Base : https://example.com/schema + Relative Pointer : /properties/foo + Dialect : http://json-schema.org/draft-07/schema# + Base Dialect : http://json-schema.org/draft-07/schema# + Parent : + Instance Location : /foo + +... + +(REFERENCE) ORIGIN: /$schema + Type : Static + Destination : http://json-schema.org/draft-07/schema + - (w/o fragment) : http://json-schema.org/draft-07/schema + - (fragment) : +``` + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "string" +} +{{}} + +{{}} +{ + "items": [ { "type": "number" } ] +} +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "price": { "type": "number" }, + "discount": { + "$ref": "#/definitions/discount" + } + }, + "definitions": { + "discount": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "number" + } + } +} +{{}} diff --git a/content/draft7/validation/additionalItems.markdown b/content/draft7/validation/additionalItems.markdown index 175dfd45..e50019ad 100644 --- a/content/draft7/validation/additionalItems.markdown +++ b/content/draft7/validation/additionalItems.markdown @@ -26,3 +26,100 @@ related: - vocabulary: validation keyword: uniqueItems --- + +The [`additionalItems`]({{< ref "draft7/validation/additionalitems" >}}) +keyword restricts array instance items not described by the _sibling_ +[`items`]({{< ref "draft7/validation/items" >}}) keyword (when [`items`]({{< +ref "draft7/validation/items" >}}) is in array form), to validate against the +given subschema. + +{{}}This keyword **only** has an effect when the sibling +[`items`]({{< ref "draft7/validation/items" >}}) keyword is set to an array of +schemas. If [`items`]({{< ref "draft7/validation/items" >}}) is not present or +is set to a schema (not an array of schemas), [`additionalItems`]({{< ref +"draft7/validation/additionalitems" >}}) has no effect and is +ignored.{{}} + +{{}}This keyword does not prevent an array instance from being +empty or having fewer items than the [`items`]({{< ref +"draft7/validation/items" >}}) array. If needed, use the [`minItems`]({{< ref +"draft7/validation/minitems" >}}) keyword to assert on the minimum bounds of the +array.{{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": [ { "type": "boolean" }, { "type": "number" } ], + "additionalItems": { "type": "string" } +} +{{}} + +{{}} +[ false, 35 ] +{{}} + +{{}} +[ false, 35, "foo", "bar" ] +{{}} + +{{}} +[ false, 35, { "foo": "bar" } ] +{{}} + +{{}} +[] +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": [ { "type": "boolean" }, { "type": "number" } ], + "additionalItems": false +} +{{}} + +{{}} +[ false, 35 ] +{{}} + +{{}} +[ false, 35, "foo" ] +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": { "type": "number" }, + "additionalItems": { "type": "string" } +} +{{}} + +{{}} +[ 1, 2, 3 ] +{{}} + +{{}} +[ 1, 2, "foo" ] +{{}} +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalItems": { "type": "string" } +} +{{}} + +{{}} +[ 1, 2, 3 ] +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/additionalProperties.markdown b/content/draft7/validation/additionalProperties.markdown index 6efd7257..6ca947a1 100644 --- a/content/draft7/validation/additionalProperties.markdown +++ b/content/draft7/validation/additionalProperties.markdown @@ -31,11 +31,11 @@ related: keyword: maxProperties --- -The `additionalProperties` keyword restricts object instance properties not -described by the _sibling_ [`properties`]({{< ref -"draft7/validation/properties" ->}}) and [`patternProperties`]({{< ref "draft7/validation/patternproperties" ->}}) keywords (if any), to validate against the given subschema. +The [`additionalProperties`]({{< ref "draft7/validation/additionalproperties" +>}}) keyword restricts object instance properties not described by the _sibling_ +[`properties`]({{< ref "draft7/validation/properties" >}}) and +[`patternProperties`]({{< ref "draft7/validation/patternproperties" >}}) +keywords (if any), to validate against the given subschema. {{}}The use of the [`properties`]({{< ref "draft7/validation/properties" >}}) keyword **does not prevent the presence of diff --git a/content/draft7/validation/allOf.markdown b/content/draft7/validation/allOf.markdown index 994f6094..a039c0e6 100644 --- a/content/draft7/validation/allOf.markdown +++ b/content/draft7/validation/allOf.markdown @@ -28,23 +28,18 @@ related: keyword: not --- -The {{}} keyword restricts +The [`allOf`]({{< ref "draft7/validation/allof" >}}) keyword restricts instances to validate against _every_ given subschema. This keyword can be thought of as a [logical conjunction](https://en.wikipedia.org/wiki/Logical_conjunction) (AND) operation, as instances are valid if they satisfy every constraint of every subschema (the intersection of the constraints). -{{}} Note that in JSON Schema [Draft 7](/draft7) and earlier -versions, any subschema declaring the `$ref` keyword is considered to be a -_reference object_ and any other sibling keyword will be silently ignored. To -avoid this, wrap subschemas with references that make use of other keywords -using the [`allOf`]({{< ref "draft7/validation/allOf" >}}) keyword. {{}} - -{{}}This keyword typically has a single use case: combining one -or more schemas through the use of (internal or external) references. If this -is not the case, prefer elevating the keywords of every subschema to the outer -schema and avoid using this keyword. {{}} +{{}}This keyword typically has a single use case: serving as an +artificial wrapper for [`$ref`]({{< ref "draft7/core/ref" >}}) keywords, to +avoid references overriding sibling keywords. If this is not the case, prefer +elevating the keywords of every subschema to the outer schema and avoid using +this keyword. {{}} This keyword is equivalent to the `&&` operator found in most programming languages. For example: @@ -124,10 +119,10 @@ result of this keyword given 3 subschemas: A, B, and C. { "$schema": "http://json-schema.org/draft-07/schema#", "allOf": [ - { "$ref": "#/$defs/foo" }, - { "$ref": "#/$defs/bar" } + { "$ref": "#/definitions/foo" }, + { "$ref": "#/definitions/bar" } ], - "$defs": { + "definitions": { "foo": { "type": "number" }, "bar": { "type": "integer" } } diff --git a/content/draft7/validation/anyOf.markdown b/content/draft7/validation/anyOf.markdown index d16f6f58..c729f2ae 100644 --- a/content/draft7/validation/anyOf.markdown +++ b/content/draft7/validation/anyOf.markdown @@ -25,3 +25,111 @@ related: - vocabulary: validation keyword: not --- + +The [`anyOf`]({{< ref "draft7/validation/anyof" >}}) keyword restricts +instances to validate against _at least one_ (but potentially multiple) of the +given subschemas. This keyword represents a [logical +disjunction](https://en.wikipedia.org/wiki/Logical_disjunction) (OR) +operation, as instances are valid if they satisfy the constraints of one or +more subschemas (the union of the constraints). + + +This keyword is equivalent to the `||` operator found in most programming +languages. For example: + +```c +bool valid = A || B || C; +``` + +As a reference, the following boolean [truth +table](https://en.wikipedia.org/wiki/Truth_table) considers the evaluation +result of this keyword given 3 subschemas: A, B, and C. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
anyOfSubschema ASubschema BSubschema C
Invalid Invalid Invalid Invalid
Valid Invalid Invalid Valid
Valid Invalid Valid Invalid
Valid Invalid Valid Valid
Valid Valid Invalid Invalid
Valid Valid Invalid Valid
Valid Valid Valid Invalid
Valid Valid Valid Valid
+ +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "anyOf": [ + { "required": [ "foo" ] }, + { "required": [ "bar" ] } + ] +} +{{}} + +{{}} +{ "foo": 1 } +{{}} + +{{}} +{ "bar": 2 } +{{}} + +{{}} +{ "foo": 1, "bar": 2 } +{{}} + +{{}} +{ "extra": 4 } +{{}} diff --git a/content/draft7/validation/const.markdown b/content/draft7/validation/const.markdown index a70abf16..fab84646 100644 --- a/content/draft7/validation/const.markdown +++ b/content/draft7/validation/const.markdown @@ -17,3 +17,63 @@ related: - vocabulary: validation keyword: type --- + +The [`const`]({{< ref "draft7/validation/const" >}}) keyword (short for +"constant") restricts instances to a single specific JSON value of any type. + +{{}} Constraining instances to a constant value by definition +implies the given JSON type. Therefore, combining this keyword with the +[`type`]({{< ref "draft7/validation/type" >}}) keyword is redundant (or even +invalid if types don't agree), and considered an +anti-pattern.{{}} + +{{}} There are programming languages, such as JavaScript, that +[cannot distinguish between integers and real +numbers](https://2ality.com/2012/04/number-encoding.html). To accommodate for +those cases, JSON Schema considers a real number with a zero fractional part to +be equal to the corresponding integer. For example, in JSON Schema, `1` is +considered to be equal to `1.0`.{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "const": 5 +} +{{}} + +{{}} +5 +{{}} + +{{}} +5.0 +{{}} + +{{}} +1234 +{{}} + +{{}} +"Hello" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "const": { "name": "John Doe", "age": 30 } +} +{{}} + +{{}} +{ "name": "John Doe", "age": 30 } +{{}} + +{{}} +{ "name": "Jane Doe", "age": 30 } +{{}} + +{{}} +30 +{{}} diff --git a/content/draft7/validation/contains.markdown b/content/draft7/validation/contains.markdown index 716e52cb..a549c4d6 100644 --- a/content/draft7/validation/contains.markdown +++ b/content/draft7/validation/contains.markdown @@ -25,3 +25,45 @@ related: - vocabulary: validation keyword: uniqueItems --- + +The [`contains`]({{< ref "draft7/validation/contains" >}}) keyword restricts +array instances to include one or more items (at any location of the array) +that validate against the given subschema. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "contains": { + "type": "number", + "multipleOf": 2 + } +} +{{}} + +{{}} +[ "foo", 2, false, [ "bar" ], -5 ] +{{}} + +{{}} +[ "foo", 2, false, 3, 4, [ "bar" ], -5, -3.0 ] +{{}} + +{{}} +[ 2, 4, 6, 8, 10, 12 ] +{{}} + +{{}} +[ "foo", true ] +{{}} + +{{}} +[] +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/contentEncoding.markdown b/content/draft7/validation/contentEncoding.markdown index 93dc5060..27b20bb3 100644 --- a/content/draft7/validation/contentEncoding.markdown +++ b/content/draft7/validation/contentEncoding.markdown @@ -15,3 +15,90 @@ related: - vocabulary: validation keyword: contentMediaType --- + +The [`contentEncoding`]({{< ref "draft7/validation/contentencoding" >}}) +keyword signifies that a string instance value (such as a specific object +property) should be considered binary data serialised using the given encoding. +This keyword is merely descriptive and does not affect validation. The use of +this and related keywords is a common technique to encode and describe +arbitrary binary data (such as image, audio, and video) in JSON. + +{{}} + +It is recommended to set this keyword along with the [`contentMediaType`]({{< ref "draft7/validation/contentmediatype" >}}) keyword to declare the type of data +being encoded (for example, an image in PNG format). Otherwise, the receiver +must treat the instance value as a binary blob without knowing for sure the +type of information it represents. + +{{}} + +{{}} + +The JSON Schema specification prohibits implementations, for security reasons, +from automatically attempting to decode, parse, or validate encoded data +without the consumer explicitly opting in to such behaviour. If you require +this feature, consult the documentation of your tooling of choice to see if it +supports content encoding/decoding and how to enable it. + +{{}} + +{{}} + +This keyword is inspired by the +[`Content-Transfer-Encoding`](https://www.rfc-editor.org/rfc/rfc2045.html#section-6) +MIME header used in conjunction with the +[`Content-Type`](https://www.rfc-editor.org/rfc/rfc2045.html#section-5) header +to transmit non-ASCII data over e-mail. For example, if you send a PNG image as +an e-mail attachment, your e-mail client will likely send a multipart message +that includes the Base64-encoded image, sets the +[`Content-Transfer-Encoding`](https://www.rfc-editor.org/rfc/rfc2045.html#section-6) +header to +[`base64`](https://datatracker.ietf.org/doc/html/rfc2045#section-6.1), and sets +the [`Content-Type`](https://www.rfc-editor.org/rfc/rfc2045.html#section-5) +header to +[`image/png`](https://www.iana.org/assignments/media-types/image/png). + +{{}} + +[RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648) _(The Base16, Base32, +and Base64 Data Encodings)_ and [RFC +2045](https://datatracker.ietf.org/doc/html/rfc2045) _(Format of Internet +Message Bodies)_ define the following standard encodings. In the interest of +interoperability, avoid defining new content encodings. While the JSON Schema +specification does not provide explicit guidance on this, [RFC 2045 Section +6.3](https://datatracker.ietf.org/doc/html/rfc2045#section-6.3) suggests that +if a custom content encoding is really needed, it must be prefixed with `x-`. +For example, `x-my-new-encoding`. + +| Encoding | Description | Reference | +|------------|-------------------------------------------------------------------------------------------------|-----------| +| `"base64"` | Encoding scheme using a 64-character hexadecimal alphabet | [RFC 4648 Section 4](https://datatracker.ietf.org/doc/html/rfc4648#section-4) | +| `"base32"` | Encoding scheme using a 32-character hexadecimal alphabet | [RFC 4648 Section 6](https://datatracker.ietf.org/doc/html/rfc4648#section-6) | +| `"base16"` | Encoding scheme using a 16-character hexadecimal alphabet | [RFC 4648 Section 8](https://datatracker.ietf.org/doc/html/rfc4648#section-8) | +| `"7bit"` | Encoding scheme that constrains ASCII to disallow octets greater than 127, disallow `NUL`, and restricts `CR` and `LF` to `CRLF` sequences | [RFC 2045 Section 2.7](https://datatracker.ietf.org/doc/html/rfc2045#section-2.7) | +| `"8bit"` | Encoding scheme that constrains ASCII to permit octets greater than 127, disallow `NUL`, and restrict `CR` and `LF` to `CRLF` sequences | [RFC 2045 Section 2.8](https://datatracker.ietf.org/doc/html/rfc2045#section-2.8) | +| `"binary"` | Encoding scheme where any sequence of octets is allowed | [RFC 2045 Section 2.9](https://datatracker.ietf.org/doc/html/rfc2045#section-2.9) | +| `"quoted-printable"` | Encoding scheme that preserves ASCII printable characters and escapes the rest using a simple algorithm based on an hexadecimal alphabet | [RFC 2045 Section 6.7](https://datatracker.ietf.org/doc/html/rfc2045#section-6.7) | + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "contentEncoding": "base64" +} +{{}} + +{{}} +"SGVsbG8gV29ybGQ=" // Hello World +{{}} + +{{}} +"This is not Base 64" +{{}} + +{{}} +1234 +{{}} diff --git a/content/draft7/validation/contentMediaType.markdown b/content/draft7/validation/contentMediaType.markdown index 21053fe5..f4276372 100644 --- a/content/draft7/validation/contentMediaType.markdown +++ b/content/draft7/validation/contentMediaType.markdown @@ -15,3 +15,86 @@ related: - vocabulary: validation keyword: contentEncoding --- + +When the [`contentEncoding`]({{< ref "draft7/validation/contentencoding" >}}) +keyword is set, the [`contentMediaType`]({{< ref +"draft7/validation/contentmediatype" >}}) keyword signifies that a string +instance value (such as a specific object property) should be considered binary +data that represents the given type. This keyword is merely descriptive and +does not affect validation. The use of this and related keywords is a common +technique to encode and describe arbitrary binary data (such as image, audio, +and video) in JSON. + +{{}} + +It is recommended to set this keyword along with the [`contentEncoding`]({{< ref "draft7/validation/contentencoding" >}}) keyword to declare the encoding used +to serialised the data (for example, Base 64 encoding). Otherwise, the +receiver must treat the instance value as a binary blob without knowing for +sure how to decode it. + +{{}} + +{{}} + +The JSON Schema specification prohibits implementations, for security reasons, +from automatically attempting to decode, parse, or validate encoded data +without the consumer explicitly opting in to such behaviour. If you require +this feature, consult the documentation of your tooling of choice to see if it +supports content encoding/decoding and how to enable it. + +{{}} + +{{}} + +This keyword is inspired by the +[`Content-Type`](https://www.rfc-editor.org/rfc/rfc2045.html#section-5) MIME +header used in conjunction with the +[`Content-Transfer-Encoding`](https://www.rfc-editor.org/rfc/rfc2045.html#section-6) +header to transmit non-ASCII data over e-mail. For example, if you send a PNG +image as an e-mail attachment, your e-mail client will likely send a multipart +message that includes the Base64-encoded image, sets the +[`Content-Type`](https://www.rfc-editor.org/rfc/rfc2045.html#section-5) header +to [`image/png`](https://www.iana.org/assignments/media-types/image/png), and +sets the +[`Content-Transfer-Encoding`](https://www.rfc-editor.org/rfc/rfc2045.html#section-6) +header to +[`base64`](https://datatracker.ietf.org/doc/html/rfc2045#section-6.1). + +{{}} + +The Internet Assigned Numbers Authority (IANA) standards organization is the +source of truth for the exhaustive official list of registered content media +types. You can find the complete list at +[https://www.iana.org/assignments/media-types/media-types.xhtml](https://www.iana.org/assignments/media-types/media-types.xhtml). + +In the interest of interoperability, avoid using custom unregistered content +media types. If required, register a new content media type with the IANA +[here](https://www.iana.org/form/media-types). Alternatively, [RFC 2046 +Section 6](https://datatracker.ietf.org/doc/html/rfc2046#section-6) suggests +that if a custom unregistered content media type is really needed, it must live +within a registered category and prefixed with `x-`. For example, +`application/x-my-custom-media-type`. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "contentEncoding": "base64", + "contentMediaType": "text/html" +} +{{}} + +{{}} +"PHA+SlNPTiBTY2hlbWE8L3A+" //

JSON Schema

+{{
}} + +{{}} +"PFwvZm9v" // <\/foo +{{}} + +{{}} +1234 +{{}} diff --git a/content/draft7/validation/default.markdown b/content/draft7/validation/default.markdown index a96b7598..d3febc58 100644 --- a/content/draft7/validation/default.markdown +++ b/content/draft7/validation/default.markdown @@ -23,3 +23,91 @@ related: - vocabulary: validation keyword: writeOnly --- + +The [`default`]({{< ref "draft7/validation/default" >}}) keyword declares a +default instance value for a schema or any of its subschemas, typically to +support specialised tooling like documentation and form generators. This +keyword is merely descriptive and does not affect validation. + +{{}} + +The standard evaluation process will not automatically use these values to fill +in missing parts of the instance. Furthermore, the JSON Schema specification +does not provide any guidance on how this keyword should be used. + +Consult the documentation of any JSON Schema tooling you rely on to check if +and how it makes use of this keyword. + +{{}} + +{{}} + +Meta-schema validation will not check that the default values you declare are +actually valid against their respective schemas, as JSON Schema does not offer +a mechanism for meta-schemas to declare that instances validate against parts +of the same instance being evaluated. As a consequence, it is not rare for +schemas to declare invalid default values that go undetected for a long time. + +It is recommended to use the [`jsonschema +lint`](https://github.com/sourcemeta/jsonschema/blob/main/docs/lint.markdown) +command, as this linter performs further checks to detect many corner cases, +including this one. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "default": {}, + "properties": { + "language": { "default": "en" }, + "notifications": { "default": true } + } +} +{{}} + +{{}} +{ "language": "es", "notifications": false } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "email": { + "default": "johndoe@acme.com", + "$ref": "#/definitions/email-address" + } + }, + "definitions": { + "email-address": { + "type": "string", + "format": "email", + "default": "example@example.org" + } + } +} +{{}} + +{{}} +{ "email": "jane@foo.com" } +{{}} + +{{}} +{} +{{}} + +{{}} +{ "email": 1 } +{{}} diff --git a/content/draft7/validation/definitions.markdown b/content/draft7/validation/definitions.markdown index bb27049b..8765a22d 100644 --- a/content/draft7/validation/definitions.markdown +++ b/content/draft7/validation/definitions.markdown @@ -19,3 +19,61 @@ related: - vocabulary: core keyword: $ref --- + +The [`definitions`]({{< ref "draft7/validation/definitions" >}}) keyword is a +container for storing reusable schemas within a schema resource, which can be +referenced using the [`$ref`]({{< ref "draft7/core/ref" >}}) keyword. From a +software engineering point of view, this keyword is analogous to defining +_internal_ helper functions as part of a larger program. + +{{}} + +Use this keyword to reduce duplication of internal declarations within a +schema. However, **prefer extracting standalone entities that represent more +than just internal helpers into separate schema files**, and externally +referencing them instead. Otherwise, you will end up with big monolithic +schemas that are challenging to understand and maintain. + +If you need to resolve external references in advance (for distribution or +analysis), look at the [`jsonschema +bundle`](https://github.com/sourcemeta/jsonschema/blob/main/docs/bundle.markdown) +command. + +{{}} + +{{}} + +This keyword declares helper schemas for use _within_ the same schema file or +resource. Defining schema files or resources that use this keyword (and +typically no other keyword) to group common definitions for _other_ schema +files or resources to reference is considered to be an anti-pattern. If you +want to share a schema across multiple schema files or resources, that common +schema should be a standalone schema file or resource itself. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "firstName": { "$ref": "#/definitions/nonEmptyString" }, + "lastName": { "$ref": "#/definitions/nonEmptyString" } + }, + "definitions": { + "nonEmptyString": { + "type": "string", + "minLength": 1 + } + } +} +{{}} + +{{}} +{ "firstName": "John", "lastName": "Doe" } +{{}} + +{{}} +{ "firstName": "", "lastName": "" } +{{}} diff --git a/content/draft7/validation/dependencies.markdown b/content/draft7/validation/dependencies.markdown index 64bb099d..1cd1c9e1 100644 --- a/content/draft7/validation/dependencies.markdown +++ b/content/draft7/validation/dependencies.markdown @@ -25,3 +25,205 @@ related: - vocabulary: validation keyword: else --- + +The [`dependencies`]({{< ref "draft7/validation/dependencies" >}}) keyword is +used to express property-based constraints on object instances. It has two +different modes of operation depending on the type of each dependency value: + +- **Property Dependencies (Array)**: When a dependency value is set to an array + of strings, [`dependencies`]({{< ref "draft7/validation/dependencies" >}}) + restricts object instances to define certain properties if the corresponding + property key is also defined. + +- **Schema Dependencies (Schema)**: When a dependency value is set to a schema, + [`dependencies`]({{< ref "draft7/validation/dependencies" >}}) restricts + object instances to validate against the given subschema if the corresponding + property key is defined. Note that the given subschema is evaluated against + the object that defines the property dependency. + +{{}} Note that multiple potentially interrelated dependencies +can be declared at once, in which case every dependency must be transitively +fulfilled for the object instance to be valid. For example, if a schema marks +the property `B` as required if the property `A` is present and also marks the +property `C` as required if the property `B` is present, defining the property +`A` transitively requires _both_ the `B` and `C` properties to be present in +the object instance. {{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "dependencies": { + "foo": [ "bar", "baz" ] + } +} +{{}} + +{{}} +{ "foo": 1, "bar": 2, "baz": 3 } +{{}} + +{{}} +{ "foo": 1, "bar": 2 } +{{}} + +{{}} +{ "foo": 1 } +{{}} + +{{}} +{ "qux": 4 } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "dependencies": { + "foo": [ "bar" ], + "bar": [ "baz" ] + } +} +{{}} + +{{}} +{ "foo": 1, "bar": 2, "baz": 3 } +{{}} + +{{}} +{ "foo": 1, "bar": 2 } +{{}} + +{{}} +{ "bar": 2, "baz": 3 } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "dependencies": { + "foo": { "maxProperties": 2 } + } +} +{{}} + +{{}} +{ "foo": 1, "bar": 2 } +{{}} + +{{}} +{ "foo": 1, "bar": 2, "baz": 3 } +{{}} + +{{}} +{ "firstName": "John", "lastName": "Doe", "age": 50 } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "dependencies": { + "foo": { "maxProperties": 2 }, + "bar": { "minProperties": 2 } + } +} +{{}} + +{{}} +{ "foo": 1, "bar": 2 } +{{}} + +{{}} +{ "foo": 1, "bar": 2, "extra": true } +{{}} + +{{}} +{ "foo": 1 } +{{}} + +{{}} +{ "foo": 1, "name": "John Doe", "age": 50 } +{{}} + +{{}} +{ "bar": 2 } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "dependencies": { + "creditCard": [ "billingAddress" ], + "billingAddress": { "required": [ "street", "city", "zipcode" ] } + } +} +{{}} + +{{}} +{ + "creditCard": "1234-5678-9012-3456", + "billingAddress": { + "street": "123 Main St", + "city": "Anytown", + "zipcode": "12345" + } +} +{{}} + +{{}} +{ "creditCard": "1234-5678-9012-3456" } +{{}} + +{{}} +{ + "billingAddress": { + "street": "123 Main St" + } +} +{{}} + +{{}} +{ "name": "John Doe" } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/description.markdown b/content/draft7/validation/description.markdown index f4af9fc2..17034570 100644 --- a/content/draft7/validation/description.markdown +++ b/content/draft7/validation/description.markdown @@ -21,3 +21,72 @@ related: - vocabulary: validation keyword: writeOnly --- + +The [`description`]({{< ref "draft7/validation/description" >}}) keyword is a +placeholder for a longer human-readable string summary of what a schema or any +of its subschemas are about. This keyword is merely descriptive and does not +affect validation. + +{{}} + +We heavily recommend to declare this keyword at the top level of every schema, +as a human-readable longer description of what the schema is about. +Note that this keyword is meant to be to be used in conjunction with the +[`title`]({{< ref "draft7/validation/title" >}}) keyword. The idea is to +augment the short summary with a longer description, and not to avoid the +concise summary altogether. + +{{}} + +{{}} + +Tooling makers must be careful when statically traversing schemas in search of +occurrences of this keyword. It is possible for schemas to make use of this +keyword behind conditional operators, references, or any other type of keyword +that makes it hard or even impossible to correctly locate these values in all +cases. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Even Number", + "description": "This schema describes an even number", + "type": "number", + "multipleOf": 2 +} +{{}} + +{{}} +10 +{{}} + +{{}} +7 +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Number", + "type": "number", + "if": { "multipleOf": 2 }, + "then": { "description": "This is an even number" }, + "else": { "description": "This is an odd number" } +} +{{}} + +{{}} +10 +{{}} + +{{}} +7 +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/else.markdown b/content/draft7/validation/else.markdown index 23116e55..3757b2d6 100644 --- a/content/draft7/validation/else.markdown +++ b/content/draft7/validation/else.markdown @@ -28,3 +28,64 @@ related: - vocabulary: validation keyword: not --- + +The [`else`]({{< ref "draft7/validation/else" >}}) keyword restricts instances +to validate against the given subschema if the [`if`]({{< ref +"draft7/validation/if" >}}) sibling keyword failed to validate against the +instance. + +{{}} This keyword has no effect if the [`if`]({{< ref "draft7/validation/if" >}}) keyword is not declared within the same +subschema. {{}} + +{{}} The [`if`]({{< ref "draft7/validation/if" >}}), +[`then`]({{< ref "draft7/validation/then" >}}), and [`else`]({{< ref "draft7/validation/else" >}}) keywords can be thought of as imperative +variants of the [`anyOf`]({{< ref "draft7/validation/anyof" >}}) keyword, +and both approaches are equally capable of describing arbitrary conditions. +Choose the one that more elegantly describes your desired +constraints.{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": { "multipleOf": 2 }, + "else": { "minimum": 0 } +} +{{}} + +{{}} +10 +{{}} + +{{}} +-2 +{{}} + +{{}} +7 +{{}} + +{{}} +-3 +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": { "multipleOf": 2 }, + "else": { "title": "The value is an odd number" } +} +{{}} + +{{}} +7 +{{}} + +{{}} +6 +{{}} diff --git a/content/draft7/validation/enum.markdown b/content/draft7/validation/enum.markdown index d493ccb5..9c729da7 100644 --- a/content/draft7/validation/enum.markdown +++ b/content/draft7/validation/enum.markdown @@ -21,3 +21,82 @@ related: - vocabulary: validation keyword: oneOf --- + +The [`enum`]({{< ref "draft7/validation/enum" >}}) keyword restricts instances +to a finite set of possible values, which may be of different types. + +{{}} Constraining instances to a set of possible values by +definition implies the given JSON types. Therefore, combining this keyword with +the [`type`]({{< ref "draft7/validation/type" >}}) keyword is redundant (or +even invalid if types don't agree), and considered an +anti-pattern.{{}} + +{{}} There are programming languages, such as JavaScript, that +[cannot distinguish between integers and real +numbers](https://2ality.com/2012/04/number-encoding.html). To accommodate for +those cases, JSON Schema considers a real number with a zero fractional part to +be equal to the corresponding integer. For example, in JSON Schema, `1` is +considered to be equal to `1.0`.{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "enum": [ "red", "green", "blue" ] +} +{{}} + +{{}} +"green" +{{}} + +{{}} +"black" +{{}} + +{{}} +2 +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "enum": [ 1, 2.0, 3 ] +} +{{}} + +{{}} +1 +{{}} + +{{}} +2 +{{}} + +{{}} +5 +{{}} + +{{}} +"Hello" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "enum": [ "red", 123, true, { "foo": "bar" }, [ 1, 2 ], null ] +} +{{}} + +{{}} +true +{{}} + +{{}} +{ "foo": "bar" } +{{}} + +{{}} +{ "foo": "baz" } +{{}} diff --git a/content/draft7/validation/examples.markdown b/content/draft7/validation/examples.markdown index 1354a7dd..9862c520 100644 --- a/content/draft7/validation/examples.markdown +++ b/content/draft7/validation/examples.markdown @@ -23,3 +23,57 @@ related: - vocabulary: validation keyword: writeOnly --- + + +The [`examples`]({{< ref "draft7/validation/examples" >}}) keyword declares a +set of example instances for a schema or any of its subschemas, typically for +documentation purposes. This keyword is merely descriptive and does not affect +validation. + +{{}} + +Meta-schema validation will not check that the examples you declare are +actually valid against their respective schemas, as JSON Schema does not offer +a mechanism for meta-schemas to declare that instances validate against parts +of the same instance being evaluated. As a consequence, it is not rare for +schemas to declare invalid examples that go undetected for a long time. + +It is recommended to use the [`jsonschema +lint`](https://github.com/sourcemeta/jsonschema/blob/main/docs/lint.markdown) +command, as this linter performs further checks to detect many corner cases, +including this one. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "examples": [ + { "name": "John Doe", "age": 23 } + ], + "properties": { + "name": { + "type": "string", + "examples": [ "John Doe", "Jane Doe" ] + }, + "age": { + "type": "integer", + "examples": [ 1, 18, 55 ] + } + } +} +{{}} + +{{}} +{ "name": "Juan Cruz Viotti", "age": 30 } +{{}} + +{{}} +{ "age": 50 } +{{}} + +{{}} +{ "name": 1, "age": true } +{{}} diff --git a/content/draft7/validation/exclusiveMaximum.markdown b/content/draft7/validation/exclusiveMaximum.markdown index 9e35a8b3..caca7bdb 100644 --- a/content/draft7/validation/exclusiveMaximum.markdown +++ b/content/draft7/validation/exclusiveMaximum.markdown @@ -23,3 +23,76 @@ related: - vocabulary: validation keyword: multipleOf --- + +The [`exclusiveMaximum`]({{< ref "draft7/validation/exclusivemaximum" >}}) keyword restricts number instances to be strictly less +than the given number. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "exclusiveMaximum": 10 +} +{{}} + +{{}} +9.9 +{{}} + +{{}} +9 +{{}} + +{{}} +10.001 +{{}} + +{{}} +11 +{{}} + +{{}} +10.0 +{{}} + +{{}} +10 +{{}} + +{{}} +"100000" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "exclusiveMaximum": -2.1 +} +{{}} + +{{}} +-2.2 +{{}} + +{{}} +-3 +{{}} + +{{}} +-2.01 +{{}} + +{{}} +-2 +{{}} + +{{}} +-2.1 +{{}} + +{{}} +"100000" +{{}} diff --git a/content/draft7/validation/exclusiveMinimum.markdown b/content/draft7/validation/exclusiveMinimum.markdown index 5a3b4a10..ff131f9f 100644 --- a/content/draft7/validation/exclusiveMinimum.markdown +++ b/content/draft7/validation/exclusiveMinimum.markdown @@ -23,3 +23,76 @@ related: - vocabulary: validation keyword: multipleOf --- + +The [`exclusiveMinimum`]({{< ref "draft7/validation/exclusiveminimum" >}}) keyword restricts number instances to be strictly +greater than the given number. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "exclusiveMinimum": 10 +} +{{}} + +{{}} +10.1 +{{}} + +{{}} +11 +{{}} + +{{}} +9.9 +{{}} + +{{}} +9 +{{}} + +{{}} +10.0 +{{}} + +{{}} +10 +{{}} + +{{}} +"100000" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "exclusiveMinimum": -2.1 +} +{{}} + +{{}} +-2.09 +{{}} + +{{}} +-2 +{{}} + +{{}} +-2.11 +{{}} + +{{}} +-3 +{{}} + +{{}} +-2.1 +{{}} + +{{}} +"100000" +{{}} diff --git a/content/draft7/validation/format.markdown b/content/draft7/validation/format.markdown index b5920f9a..d0c7716a 100644 --- a/content/draft7/validation/format.markdown +++ b/content/draft7/validation/format.markdown @@ -16,3 +16,79 @@ changed_in: - draft4 - draft6 --- + +The `format` keyword communicates that string instances are of the given +logical type. + +{{}} By default, this keyword does not perform validation, as +validating formats is considered optional by the official JSON Schema Test +Suite. As a consequence, not many implementations support it. If validation is +desired, the best practice is to combine this keyword with the [`pattern`]({{< ref "draft7/validation/pattern" >}}) keyword. This guarantees interoperable +and unambiguous behavior across JSON Schema implementations. +{{}} + +{{}} While [technically +allowed](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.2) +by the JSON Schema specification, extending this keyword with custom formats is +considered to be an anti-pattern that can introduce interoperability issues and +undefined behavior. As a best practice, stick to standardised formats. If +needed, introduce a new keyword for custom string logical +types.{{}} + +{{}} This keyword and its validation guarantees are a common +source of confusion of the JSON Schema specification across versions. + +Since the introduction of this keyword, the JSON Schema specifications +clarified that validation was not mandatory. However, the majority of older +Schema implementations did support validation, leading schema-writers to rely +on it. At the same time, a second problem emerged: implementations often didn't +agree on the strictness of validation, mainly on complex logical types like +e-mail addresses, leading to various interoperability issues. + +To avoid the gray areas of this keyword, we recommend only treating it as +semantic metadata, never enabling validation support at the implementation +level (even if supported), and performing validation using the [`pattern`]({{< +ref "draft7/validation/pattern" >}}) keyword. {{}} + +The supported formats are the following. + +| Format | Category | Specification | +|---------------------------|----------------------|---------------| +| `"date-time"` | Time | [JSON Schema Draft 7 Validation Section 7.3.1](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.1) | +| `"date"` | Time | [JSON Schema Draft 7 Validation Section 7.3.1](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.1) | +| `"time"` | Time | [JSON Schema Draft 7 Validation Section 7.3.1](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.1) | +| `"email"` | Emails | [JSON Schema Draft 7 Validation Section 7.3.2](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.2) | +| `"idn-email"` | Emails | [JSON Schema Draft 7 Validation Section 7.3.2](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.2) | +| `"hostname"` | Hostnames | [JSON Schema Draft 7 Validation Section 7.3.3](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.3) | +| `"idn-hostname"` | Hostnames | [JSON Schema Draft 7 Validation Section 7.3.3](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.3) | +| `"ipv4"` | IP Addresses | [JSON Schema Draft 7 Validation Section 7.3.4](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.4) | +| `"ipv6"` | IP Addresses | [JSON Schema Draft 7 Validation Section 7.3.4](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.4) | +| `"uri"` | Resource Identifiers | [JSON Schema Draft 7 Validation Section 7.3.5](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.5) | +| `"uri-reference"` | Resource Identifiers | [JSON Schema Draft 7 Validation Section 7.3.5](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.5) | +| `"iri"` | Resource Identifiers | [JSON Schema Draft 7 Validation Section 7.3.5](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.5) | +| `"iri-reference"` | Resource Identifiers | [JSON Schema Draft 7 Validation Section 7.3.5](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.5) | +| `"uri-template"` | Resource Identifiers | [JSON Schema Draft 7 Validation Section 7.3.6](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.6) | +| `"json-pointer"` | JSON Pointer | [JSON Schema Draft 7 Validation Section 7.3.7](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.7) | +| `"relative-json-pointer"` | JSON Pointer | [JSON Schema Draft 7 Validation Section 7.3.7](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.7) | +| `"regex"` | Regular Expressions | [JSON Schema Draft 7 Validation Section 7.3.8](https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.7.3.8) | + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "format": "email" +} +{{}} + +{{}} +"john.doe@example.com" +{{}} + +{{}} +"foo-bar" +{{}} + +{{}} +45 +{{}} diff --git a/content/draft7/validation/if.markdown b/content/draft7/validation/if.markdown index 03afb9b6..7bad7cbf 100644 --- a/content/draft7/validation/if.markdown +++ b/content/draft7/validation/if.markdown @@ -26,3 +26,139 @@ related: - vocabulary: validation keyword: not --- + +The [`if`]({{< ref "draft7/validation/if" >}}) keyword introduces a subschema +whose evaluation result restricts instances to validate against the +[`then`]({{< ref "draft7/validation/then" >}}) or [`else`]({{< ref +"draft7/validation/else" >}}) sibling subschemas (if present). Note that the +evaluation outcome of this subschema controls which other subschema to apply (if +any) but has no direct effect on the overall validation result. + +{{}} The [`if`]({{< ref "draft7/validation/if" >}}), +[`then`]({{< ref "draft7/validation/then" >}}), and [`else`]({{< ref "draft7/validation/else" >}}) keywords can be thought of as imperative variants +of the [`anyOf`]({{< ref "draft7/validation/anyof" >}}) keyword, and both +approaches are equally capable of describing arbitrary conditions. Choose the +one that more elegantly describes your desired +constraints.{{}} + +{{}} This keyword has no effect if neither the [`then`]({{< ref +"draft7/validation/then" >}}) nor [`else`]({{< ref "draft7/validation/else" +>}}) keywords are declared within the same subschema.{{}} + +The [`if`]({{< ref "draft7/validation/if" >}}), [`then`]({{< ref +"draft7/validation/then" >}}), and [`else`]({{< ref "draft7/validation/else" +>}}) keywords are equivalent to the `?` and `:` ternary conditional operators +found in most programming languages. For example: + +```c +bool valid = if_schema ? then_schema : else_schema; +``` + +JSON Schema is a [constraint-driven +language](https://modern-json-schema.com/json-schema-is-a-constraint-system). +Therefore, omitting either the [`then`]({{< ref "draft7/validation/then" >}}) +or the [`else`]({{< ref "draft7/validation/else" >}}) keywords is equivalent to +setting the corresponding part of the ternary conditional operation to the +boolean true. In other words, undefined consequent or alternative paths lead to +success. For example: + +```c +// If `then` is missing +bool valid = if_schema ? true : else_schema; +// If `else` is missing +bool valid = if_schema ? then_schema : true; +``` + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": { "multipleOf": 2 }, + "then": { "minimum": 0 }, + "else": { "exclusiveMaximum": 0 } +} +{{}} + +{{}} +10 +{{}} + +{{}} +-2 +{{}} + +{{}} +7 +{{}} + +{{}} +-3 +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": { "multipleOf": 2 }, + "then": { "minimum": 0 } +} +{{}} + +{{}} +10 +{{}} + +{{}} +-2 +{{}} + +{{}} +7 +{{}} + +{{}} +-3 +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": { "multipleOf": 2 }, + "else": { "minimum": 0 } +} +{{}} + +{{}} +10 +{{}} + +{{}} +-2 +{{}} + +{{}} +7 +{{}} + +{{}} +-3 +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": { "items": { "type": "string" } } +} +{{}} + +{{}} +[ "foo", "bar", "baz" ] +{{}} + +{{}} +[ 1, 2, 3 ] +{{}} diff --git a/content/draft7/validation/items.markdown b/content/draft7/validation/items.markdown index 315a4c2f..63222a92 100644 --- a/content/draft7/validation/items.markdown +++ b/content/draft7/validation/items.markdown @@ -31,3 +31,107 @@ related: - vocabulary: validation keyword: uniqueItems --- + +The [`items`]({{< ref "draft7/validation/items" >}}) keyword is used to +validate array items and has two different modes of operation depending on the +type of its value: + +- **Schema**: When set to a schema, [`items`]({{< ref "draft7/validation/items" + >}}) validates that all items in the array instance validate against the + given subschema. + +- **Array**: When set to an array of schemas, [`items`]({{< ref + "draft7/validation/items" >}}) validates each item in the array instance + against the subschema at the corresponding position. Items beyond the length + of the [`items`]({{< ref "draft7/validation/items" >}}) array can be + validated using the [`additionalItems`]({{< ref + "draft7/validation/additionalitems" >}}) keyword. + +{{}}This keyword does not prevent an array instance from being +empty. If needed, use the [`minItems`]({{< ref "draft7/validation/minitems" >}}) to assert on the minimum bounds of the array.{{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": { "type": "number" } +} +{{}} + +{{}} +[ 1, -3.4, 54 ] +{{}} + +{{}} +[] +{{}} + +{{}} +[ 1, -3.4, 54, "foo" ] +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": [ { "type": "boolean" }, { "type": "number" } ] +} +{{}} + +{{}} +[ false, 35 ] +{{}} + +{{}} +[ false, 35, "foo", "bar" ] +{{}} + +{{}} +[ "not a boolean", 35 ] +{{}} + +{{}} +[ false, "not a number" ] +{{}} + +{{}} +[] +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": [ { "type": "boolean" }, { "type": "number" } ], + "additionalItems": { "type": "string" } +} +{{}} + +{{}} +[ false, 35 ] +{{}} + +{{}} +[ false, 35, "foo", "bar" ] +{{}} + +{{}} +[ false, 35, { "foo": "bar" } ] +{{}} + +{{}} +[] +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/maxItems.markdown b/content/draft7/validation/maxItems.markdown index 6c80061e..6c8ce72e 100644 --- a/content/draft7/validation/maxItems.markdown +++ b/content/draft7/validation/maxItems.markdown @@ -21,3 +21,41 @@ related: - vocabulary: validation keyword: contains --- + +The [`maxItems`]({{< ref "draft7/validation/maxitems" >}}) keyword restricts array instances to consists of an inclusive +maximum numbers of items. + +{{}} The presence of this keyword does not depend on the +presence of the [`items`]({{< ref "draft7/validation/items" >}}) keyword. +{{}} + +{{}}To restrict array instances to the empty array, prefer using +the [`const`]({{< ref "draft7/validation/const" >}}) keyword instead of +setting this keyword to `0`. {{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "maxItems": 3 +} +{{}} + +{{}} +[ 1, 2, 3, 4 ] +{{}} + +{{}} +[ 1, true, "hello" ] +{{}} + +{{}} +[ false, "foo" ] +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/maxLength.markdown b/content/draft7/validation/maxLength.markdown index 703402ce..3097e1be 100644 --- a/content/draft7/validation/maxLength.markdown +++ b/content/draft7/validation/maxLength.markdown @@ -19,3 +19,56 @@ related: - vocabulary: validation keyword: format --- + +The [`maxLength`]({{< ref "draft7/validation/maxlength" >}}) keyword restricts string instances to consists of an inclusive +maximum number of [Unicode](https://unicode.org) code-points (logical +characters), which is not necessarily the same as the number of bytes in the +string. + +{{}} While the [IETF RFC +8259](https://www.rfc-editor.org/rfc/rfc8259) JSON standard recommends the use +of [UTF-8](https://en.wikipedia.org/wiki/UTF-8), other Unicode encodings are +permitted. Therefore a JSON string may be represented in up to 4x the number of +bytes as its number of code-points (assuming +[UTF-32](https://en.wikipedia.org/wiki/UTF-32) as the upper bound). + +JSON Schema does not provide a mechanism to assert on the byte size of a JSON +string, as this is an implementation-dependent property of the JSON parser in +use. {{}} + +{{}} Be careful when making use of this keyword to +inadvertently assert on the byte length of JSON strings before inserting them +into byte-sensitive destinations like fixed-size buffers. Always assume that +the byte length of a JSON string can arbitrary larger that the number of +logical characters.{{}} + +{{}}To restrict string instances to the empty string, prefer +using the [`const`]({{< ref "draft7/validation/const" >}}) keyword instead of +setting this keyword to `0`. {{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "maxLength": 3 +} +{{}} + +{{}} +"foo" +{{}} + +{{}} +"こんにちは" +{{}} + +{{}} +"hi" +{{}} + +{{}} +55 +{{}} diff --git a/content/draft7/validation/maxProperties.markdown b/content/draft7/validation/maxProperties.markdown index 12d258fb..bb8c31bb 100644 --- a/content/draft7/validation/maxProperties.markdown +++ b/content/draft7/validation/maxProperties.markdown @@ -21,3 +21,41 @@ related: - vocabulary: validation keyword: additionalProperties --- + +The [`maxProperties`]({{< ref "draft7/validation/maxproperties" >}}) keyword restricts object instances to consists of an +inclusive maximum numbers of properties. + +{{}} The presence of this keyword does not depend on the +presence of the [`properties`]({{< ref "draft7/validation/properties" >}}) +keyword. {{}} + +{{}}To restrict object instances to the empty object, prefer +using the [`const`]({{< ref "draft7/validation/const" >}}) keyword instead of +setting this keyword to `0`. {{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "maxProperties": 2 +} +{{}} + +{{}} +{ "foo": 1, "bar": 2, "baz": 3 } +{{}} + +{{}} +{ "foo": 1, "bar": 2 } +{{}} + +{{}} +{ "foo": 1 } +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/maximum.markdown b/content/draft7/validation/maximum.markdown index 6be2ef77..a558aa1a 100644 --- a/content/draft7/validation/maximum.markdown +++ b/content/draft7/validation/maximum.markdown @@ -21,3 +21,76 @@ related: - vocabulary: validation keyword: multipleOf --- + +The [`maximum`]({{< ref "draft7/validation/maximum" >}}) keyword restricts number instances to be less than or equal to +the given number. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "maximum": 10 +} +{{}} + +{{}} +9.9 +{{}} + +{{}} +9 +{{}} + +{{}} +10.001 +{{}} + +{{}} +11 +{{}} + +{{}} +10.0 +{{}} + +{{}} +10 +{{}} + +{{}} +"100000" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "maximum": -2.1 +} +{{}} + +{{}} +-2.2 +{{}} + +{{}} +-3 +{{}} + +{{}} +-2.01 +{{}} + +{{}} +-2 +{{}} + +{{}} +-2.1 +{{}} + +{{}} +"100000" +{{}} diff --git a/content/draft7/validation/minItems.markdown b/content/draft7/validation/minItems.markdown index d6a52e30..955f7872 100644 --- a/content/draft7/validation/minItems.markdown +++ b/content/draft7/validation/minItems.markdown @@ -23,3 +23,37 @@ related: - vocabulary: validation keyword: contains --- + +The [`minItems`]({{< ref "draft7/validation/minitems" >}}) keyword restricts array instances to consists of an inclusive +minimum numbers of items. + +{{}} The presence of this keyword does not depend on the +presence of the [`items`]({{< ref "draft7/validation/items" >}}) keyword. +{{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "minItems": 3 +} +{{}} + +{{}} +[ 1, 2, 3, 4 ] +{{}} + +{{}} +[ 1, true, "hello" ] +{{}} + +{{}} +[ false, "foo" ] +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/minLength.markdown b/content/draft7/validation/minLength.markdown index fa23f47a..1110530a 100644 --- a/content/draft7/validation/minLength.markdown +++ b/content/draft7/validation/minLength.markdown @@ -21,3 +21,45 @@ related: - vocabulary: validation keyword: format --- + +The [`minLength`]({{< ref "draft7/validation/minlength" >}}) keyword restricts string instances to consists of an inclusive +minimum number of [Unicode](https://unicode.org) code-points (logical +characters), which is not necessarily the same as the number of bytes in the +string. + +{{}} While the [IETF RFC +8259](https://www.rfc-editor.org/rfc/rfc8259) JSON standard recommends the use +of [UTF-8](https://en.wikipedia.org/wiki/UTF-8), other Unicode encodings are +permitted. Therefore a JSON string may be represented in more bytes than its +number of code-points. + +JSON Schema does not provide a mechanism to assert on the byte size of a JSON +string, as this is an implementation-dependent property of the JSON parser in +use. {{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "minLength": 3 +} +{{}} + +{{}} +"foo" +{{}} + +{{}} +"こんにちは" +{{}} + +{{}} +"hi" +{{}} + +{{}} +55 +{{}} diff --git a/content/draft7/validation/minProperties.markdown b/content/draft7/validation/minProperties.markdown index daf98cb1..61455b5d 100644 --- a/content/draft7/validation/minProperties.markdown +++ b/content/draft7/validation/minProperties.markdown @@ -23,3 +23,37 @@ related: - vocabulary: validation keyword: additionalProperties --- + +The [`minProperties`]({{< ref "draft7/validation/minproperties" >}}) keyword restricts object instances to consists of an +inclusive minimum numbers of properties. + +{{}} The presence of this keyword does not depend on the +presence of the [`properties`]({{< ref "draft7/validation/properties" >}}) +keyword. {{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "minProperties": 2 +} +{{}} + +{{}} +{ "foo": 1, "bar": 2, "baz": 3 } +{{}} + +{{}} +{ "foo": 1, "bar": 2 } +{{}} + +{{}} +{ "foo": 1 } +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/minimum.markdown b/content/draft7/validation/minimum.markdown index 6108fdaf..344a509c 100644 --- a/content/draft7/validation/minimum.markdown +++ b/content/draft7/validation/minimum.markdown @@ -21,3 +21,76 @@ related: - vocabulary: validation keyword: multipleOf --- + +The [`minimum`]({{< ref "draft7/validation/minimum" >}}) keyword restricts number instances to be greater than or equal to +the given number. + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "minimum": 10 +} +{{}} + +{{}} +10.1 +{{}} + +{{}} +11 +{{}} + +{{}} +9.9 +{{}} + +{{}} +9 +{{}} + +{{}} +10.0 +{{}} + +{{}} +10 +{{}} + +{{}} +"100000" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "minimum": -2.1 +} +{{}} + +{{}} +-2.09 +{{}} + +{{}} +-2 +{{}} + +{{}} +-2.11 +{{}} + +{{}} +-3 +{{}} + +{{}} +-2.1 +{{}} + +{{}} +"100000" +{{}} diff --git a/content/draft7/validation/multipleOf.markdown b/content/draft7/validation/multipleOf.markdown index 32f49e55..d66f3a2c 100644 --- a/content/draft7/validation/multipleOf.markdown +++ b/content/draft7/validation/multipleOf.markdown @@ -23,3 +23,110 @@ related: - vocabulary: validation keyword: minimum --- + +The [`multipleOf`]({{< ref "draft7/validation/multipleof" >}}) keyword +restricts number instances to be multiples of the given number. Note that the +number `0` is a multiple of every number, as for every number `k`, the +multiplication `0 * k` yield an integer value (in this case always 0). This case +is not to be confused with [division by +zero](https://en.wikipedia.org/wiki/Division_by_zero), which is not a permitted +operation in most computer systems. + +{{}}Setting this keyword to negative powers of 10, such as +`0.01` (10^-2), `0.001` (10^-3), and `0.0001` (10^-4), is a common mechanism to +control the maximum number of digits in the fractional part of a real number. +For example, `1.2` and `-12.34` are multiples of `0.01`, but `1.234` is +not.{{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "multipleOf": 5 +} +{{}} + +{{}} +10 +{{}} + +{{}} +-5 +{{}} + +{{}} +15.0 +{{}} + +{{}} +8 +{{}} + +{{}} +0 +{{}} + +{{}} +"100000" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "multipleOf": 2.3 +} +{{}} + +{{}} +6.9 +{{}} + +{{}} +-4.6 +{{}} + +{{}} +2.4 +{{}} + +{{}} +0 +{{}} + +{{}} +"100000" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "multipleOf": 0.01 +} +{{}} + +{{}} +2 +{{}} + +{{}} +5.1 +{{}} + +{{}} +-12.34 +{{}} + +{{}} +1.234 +{{}} + +{{}} +0 +{{}} + +{{}} +"100000" +{{}} diff --git a/content/draft7/validation/not.markdown b/content/draft7/validation/not.markdown index 12f8958a..5ecf6590 100644 --- a/content/draft7/validation/not.markdown +++ b/content/draft7/validation/not.markdown @@ -27,3 +27,58 @@ related: - vocabulary: validation keyword: else --- + +The [`not`]({{< ref "draft7/validation/not" >}}) keyword restricts +instances to fail validation against the given subschema. This keyword +represents a [logical negation](https://en.wikipedia.org/wiki/Negation) (NOT) +operation. In other words, the instance successfully validates against the +schema only if it does not match the given subschema. + + +{{}} Avoid the use of this keyword (usually negating the +[`required`]({{< ref "draft7/validation/required" >}}) keyword) to prohibit +specific object properties from being defined. Instead, use the +[`properties`]({{< ref "draft7/validation/properties" >}}) keyword and set +the disallowed object properties to the `false` boolean +schema.{{}} + +This keyword is equivalent to the `!` operator found in most programming +languages. For example: + +```c +bool valid = !not_schema; +``` + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "not": { + "const": "Prohibited" + } +} +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +"Prohibited" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "not": { + "type": "string", + "minLength": 10, + "maxLength": 9 + } +} +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/oneOf.markdown b/content/draft7/validation/oneOf.markdown index 2f2d9e48..430aec24 100644 --- a/content/draft7/validation/oneOf.markdown +++ b/content/draft7/validation/oneOf.markdown @@ -25,3 +25,128 @@ related: - vocabulary: validation keyword: not --- + +The [`oneOf`]({{< ref "draft7/validation/oneof" >}}) keyword restricts +instances to validate against _exactly one_ (and only one) of the given +subschemas and fail on the rest. This keyword represents a [logical exclusive +disjunction](https://en.wikipedia.org/wiki/Exclusive_or) (XOR) operation. In +practice, the vast majority of schemas don't require exclusive disjunction +semantics but a simple disjunction. If you are not sure, the [`anyOf`]({{< ref +"draft7/validation/anyof" >}}) keyword is probably a better fit. + +{{}} + +Avoid this keyword unless you absolutely need exclusive disjunction +semantics, which is rarely the case. As its name implies, this keyword +enforces the instance to be valid against **only one of its subschemas**. +Therefore, a JSON Schema implementation will exhaustively evaluate every +subschema to make sure the rest fails, potentially introducing unnecessary +computational overhead. + +{{}} + +This keyword is equivalent to the following complex boolean construct that +combines the `||`, `&&`, and `!` operators found in most programming +languages: + +```c +bool valid = (A && !B && !C) || (!A && B && !C) || (!A && !B && C); +``` + +As a reference, the following boolean [truth +table](https://en.wikipedia.org/wiki/Truth_table) considers the evaluation +result of this keyword given 3 subschemas: A, B, and C. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
oneOfSubschema ASubschema BSubschema C
Invalid Invalid Invalid Invalid
Valid Invalid Invalid Valid
Valid Invalid Valid Invalid
Invalid Invalid Valid Valid
Valid Valid Invalid Invalid
Invalid Valid Invalid Valid
Invalid Valid Valid Invalid
Invalid Valid Valid Valid
+ +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "oneOf": [ + { "required": [ "foo" ] }, + { "required": [ "bar" ] }, + { "required": [ "baz" ] } + ] +} +{{}} + +{{}} +{ "foo": 1 } +{{}} + +{{}} +{ "bar": 2 } +{{}} + +{{}} +{ "foo": 1, "bar": 2 } +{{}} + +{{}} +{ "foo": 1, "bar": 2, "baz": 3 } +{{}} + +{{}} +{ "extra": 4 } +{{}} diff --git a/content/draft7/validation/pattern.markdown b/content/draft7/validation/pattern.markdown index 1291e114..043af3a7 100644 --- a/content/draft7/validation/pattern.markdown +++ b/content/draft7/validation/pattern.markdown @@ -23,3 +23,54 @@ related: - vocabulary: validation keyword: patternProperties --- + +The [`pattern`]({{< ref "draft7/validation/pattern" >}}) keyword restricts +string instances to match the given regular expression. + +{{}} While the specification suggests the use of +[ECMA-262](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/) +regular expressions for interoperability purposes, the use of different +flavours like PCRE or POSIX (Basic or Extended) is permitted. Also, the +specification does not impose the use of any particular regular expression +flag. By convention (and somewhat enforced by the official JSON Schema test +suite), regular expressions are not implicitly +[anchored](https://www.regular-expressions.info/anchors.html) and are always +treated as case-sensitive. It is also common for the +[`DOTALL`](https://tc39.es/ecma262/multipage/text-processing.html#sec-get-regexp.prototype.dotAll) +flag to be enabled, permitting the dot character class to match new lines. + +To avoid interoperability issues, stick to +[ECMA-262](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/), +and don't assume the use of any regular expression flag. {{}} + +{{}} Regular expressions often make use of characters that need +to be escaped when making use of them as part of JSON strings. For example, the +*reverse solidus* character (more commonly known as the backslash character) +and the *double quote* character need to be escaped. Failure to do so will +result in an invalid JSON document. Applications to work with regular +expressions, like [Regex Forge](https://regexforge.com), typically provide +convenient functionality to copy a regular expression for use in JSON. +{{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" +} +{{}} + +{{}} +"john.doe@example.com" +{{}} + +{{}} +"foo" +{{}} + +{{}} +1234 +{{}} diff --git a/content/draft7/validation/patternProperties.markdown b/content/draft7/validation/patternProperties.markdown index 102c6d57..8b48b617 100644 --- a/content/draft7/validation/patternProperties.markdown +++ b/content/draft7/validation/patternProperties.markdown @@ -32,3 +32,135 @@ related: - vocabulary: validation keyword: maxProperties --- + +The [`patternProperties`]({{< ref "draft7/validation/patternproperties" >}}) +keyword restricts properties of an object instance that match certain regular +expressions to match their corresponding subschemas definitions. + +{{}} This keyword is evaluated independently of the +[`properties`]({{< ref "draft7/validation/properties" >}}) keyword. If an +object property is described by both keywords, then both subschemas must +successfully validate against the given property for validation to succeed. +Furthermore, an instance property may match more than one regular expression +set with this keyword, in which case the property is expected to validate +against all matching subschemas.{{}} + +{{}} While the specification suggests the use of +[ECMA-262](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/) +regular expressions for interoperability purposes, the use of different +flavours like PCRE or POSIX (Basic or Extended) is permitted. Also, the +specification does not impose the use of any particular regular expression +flag. By convention (and somewhat enforced by the official JSON Schema test +suite), regular expressions are not implicitly +[anchored](https://www.regular-expressions.info/anchors.html) and are always +treated as case-sensitive. It is also common for the +[`DOTALL`](https://tc39.es/ecma262/multipage/text-processing.html#sec-get-regexp.prototype.dotAll) +flag to be enabled, permitting the dot character class to match new lines. + +To avoid interoperability issues, stick to +[ECMA-262](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/), +and don't assume the use of any regular expression flag. {{}} + +{{}} Regular expressions often make use of characters that need +to be escaped when making use of them as part of JSON strings. For example, the +*reverse solidus* character (more commonly known as the backslash character) +and the *double quote* character need to be escaped. Failure to do so will +result in an invalid JSON document. Applications to work with regular +expressions, like [Regex Forge](https://regexforge.com), typically provide +convenient functionality to copy a regular expression for use in JSON. +{{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "patternProperties": { + "^[a-z]+$": { "type": "integer" } + } +} +{{}} + +{{}} +{ "foo": 1, "bar": 2, "baz": 3 } +{{}} + +{{}} +{ "CamelCase": true, "alphanumeric123": "anything is valid" } +{{}} + +{{}} +{} +{{}} + +{{}} +{ "foo": "should have been an integer" } +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "patternProperties": { + "^f": { "type": "string" }, + "o$": { "minLength": 3 } + } +} +{{}} + +{{}} +{ "foo": "long string" } +{{}} + +{{}} +{ "boo": 1 } +{{}} + +{{}} +{ "foo": "xx" } +{{}} + +{{}} +{ "boo": "xx" } +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "patternProperties": { + "^f": { "minLength": 3 } + }, + "properties": { + "foo": { "type": "string" } + } +} +{{}} + +{{}} +{ "foo": "long string" } +{{}} + +{{}} +{ "football": 3 } +{{}} + +{{}} +{ "foo": "xx" } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/properties.markdown b/content/draft7/validation/properties.markdown index bcdb31c0..7c87d62b 100644 --- a/content/draft7/validation/properties.markdown +++ b/content/draft7/validation/properties.markdown @@ -30,3 +30,99 @@ related: - vocabulary: validation keyword: maxProperties --- + +The [`properties`]({{< ref "draft7/validation/properties" >}}) keyword +restricts properties of an object instance, when present, to match their +corresponding subschemas definitions. + +{{}}The use of this keyword **does not prevent the presence of +other properties** in the object instance and **does not enforce the presence +of the declared properties**. In other words, additional data that is not +explicitly prohibited is permitted by default. This is intended behaviour to +ease schema evolution (open schemas are backwards compatible by default) and to +enable highly-expressive constraint-driven schemas. + +If you want to restrict instances to only contain the properties you declared, +you must set the [`additionalProperties`]({{< ref "draft7/validation/additionalproperties" >}}) keyword to the boolean schema +`false`, and if you want to enforce the presence of certain properties, you +must use the [`required`]({{< ref "draft7/validation/required" >}}) keyword +accordingly. {{}} + +{{}}Setting properties defined by this keyword to the boolean +schema `false` is an common trick to express that such properties are +forbidden. This is considered more elegant (and usually more performant) than +using the [`not`]({{< ref "draft7/validation/not" >}}) applicator to negate +the [`required`]({{< ref "draft7/validation/required" >}}) keyword. However, +setting properties defined by this keyword to the boolean `true` is considered +to be redundant and an anti-pattern, as additional properties are permitted by +default. {{}} + +{{}} This keyword is evaluated independently of the +[`patternProperties`]({{< ref "draft7/validation/patternproperties" >}}) +keyword. If an object property is described by both keywords, then both schemas +must successfully validate against the given property for validation to +succeed. {{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "name": { "type": "string" }, + "age": { "type": "integer" } + } +} +{{}} + +{{}} +{ "name": "John Doe", "age": 50 } +{{}} + +{{}} +{ "name": "John Doe" } +{{}} + +{{}} +{} +{{}} + +{{}} +{ "name": "John Doe", "age": "this should have been an integer" } +{{}} + +{{}} +{ "name": 999 } +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "forbidden": false, + "permitted": true + } +} +{{}} + +{{}} +{ "permitted": "anything is valid" } +{{}} + +{{}} +{ "foo": "bar", "baz": 2 } +{{}} + +{{}} +{ "forbidden": 1 } +{{}} + +{{}} +{ "forbidden": 1, "permitted": 2 } +{{}} diff --git a/content/draft7/validation/propertyNames.markdown b/content/draft7/validation/propertyNames.markdown index 60fa45a1..a82bbb48 100644 --- a/content/draft7/validation/propertyNames.markdown +++ b/content/draft7/validation/propertyNames.markdown @@ -27,3 +27,94 @@ related: - vocabulary: validation keyword: maxProperties --- + +The [`propertyNames`]({{< ref "draft7/validation/propertynames" >}}) keyword +restricts object instances to only define properties whose names match the given +schema. This keyword is evaluated against _every_ property of the object +instance, independently of keywords that indirectly introduce property names +such as [`properties`]({{< ref "draft7/validation/properties" >}}) and +[`patternProperties`]({{< ref "draft7/validation/patternproperties" >}}). + +{{}} As per the JSON grammar, the name of an object property +must be a string. Therefore, setting this keyword to a schema that makes use +of keywords that only apply to types other than strings (such as the +[`properties`]({{< ref "draft7/validation/properties" >}}) keyword) is +either meaningless or leads to unsatisfiable schemas. Conversely, explicitly +setting the [`type`]({{< ref "draft7/validation/type" >}}) keyword to +`string` is redundant. {{}} + +{{}} This keyword is useful when describing JSON objects whose +properties cannot be known in advance. For example, allowing extensions that +must adhere to a certain name convention. If that's not the case, prefer +explicitly listing every permitted property using the [`properties`]({{< ref "draft7/validation/properties" >}}) or [`patternProperties`]({{< ref "draft7/validation/patternproperties" >}}) keywords, and potentially closing +the object by setting the [`additionalProperties`]({{< ref "draft7/validation/additionalproperties" >}}) keyword to `false`. +{{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "propertyNames": { "pattern": "^[a-z]*$" } +} +{{}} + +{{}} +{ "foo": "bar" } +{{}} + +{{}} +{} +{{}} + +{{}} +{ "CamelCase": true, "alphanumeric123": false } +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "propertyNames": { "type": "array" } +} +{{}} + +{{}} +{ "foo": "bar" } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "propertyNames": { "pattern": "^b" }, + "properties": { + "foo": { "type": "integer" }, + "bar": { "type": "integer" } + } +} +{{}} + +{{}} +{ "foo": 1 } +{{}} + +{{}} +{ "bar": "should have been an integer" } +{{}} + +{{}} +{ "baz": "qux" } +{{}} diff --git a/content/draft7/validation/readOnly.markdown b/content/draft7/validation/readOnly.markdown index a1460ac4..59fd825a 100644 --- a/content/draft7/validation/readOnly.markdown +++ b/content/draft7/validation/readOnly.markdown @@ -23,3 +23,87 @@ related: - vocabulary: validation keyword: default --- + +The [`readOnly`]({{< ref "draft7/validation/readonly" >}}) keyword, when set to `true`, signifies that an instance value +(such as a specific object property) cannot be modified or removed, whatever +that means in the context of the system. For example, form generators may rely +on this keyword to mark the corresponding input as read only. This keyword provides metadata for documentation purposes and does not affect validation. + +{{}} + +Avoid setting this keyword to the default value `false`. If an instance value +is not considered to be read only, the best practice is to omit the use of this +keyword altogether. + +Also avoid simultaneously setting this keyword and the [`writeOnly`]({{< ref "draft7/validation/writeonly" >}}) keyword to `true` for the same instance +location, resulting in ambiguous semantics. + +{{}} + +{{}} + +Tooling makers must be careful when statically traversing schemas in search of +occurrences of this keyword. It is possible for schemas to make use of this +keyword behind conditional operators, references, or any other type of keyword +that makes it hard or even impossible to correctly locate these values in all +cases. + +For example, an instance property might only be read only under certain +conditions determined by a dynamic operator like [`anyOf`]({{< ref "draft7/validation/anyof" >}}). + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "id": { "type": "integer", "readOnly": true }, + "value": { "type": "integer" } + } +} +{{}} + +{{}} +{ "id": 1234, "value": 5 } +{{}} + +{{}} +{ "value": 5 } +{{}} + +{{}} +{ "id": 1234, "value": null } +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "id": { "type": "integer" }, + "value": { "type": "integer" } + }, + "dependencies": { + "value": { + "properties": { "id": { "readOnly": true } } + } + } +} +{{}} + +{{}} +{ "id": 1234, "value": 5 } +{{}} + +{{}} +{ "value": 5 } +{{}} + +{{}} +{ "id": 1234 } +{{}} + +{{}} +{ "value": null } +{{}} diff --git a/content/draft7/validation/required.markdown b/content/draft7/validation/required.markdown index 726a3ec6..422d32db 100644 --- a/content/draft7/validation/required.markdown +++ b/content/draft7/validation/required.markdown @@ -23,3 +23,79 @@ related: - vocabulary: validation keyword: minProperties --- + +The [`required`]({{< ref "draft7/validation/required" >}}) keyword restricts +object instances to define the given set of properties. + +{{}} The presence of this keyword does not depend on the +presence of the [`properties`]({{< ref "draft7/validation/properties" >}}) +keyword. The [`required`]({{< ref "draft7/validation/required" >}}) keyword +mandates that certain properties are present (independently of their value), +while the [`properties`]({{< ref "draft7/validation/properties" >}}) keyword +describes the value of such properties when present.{{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "required": [ "foo", "bar", "baz" ] +} +{{}} + +{{}} +{ "foo": 1, "bar": 2, "baz": 3 } +{{}} + +{{}} +{ "foo": 1, "bar": 2, "baz": 3, "extra": true } +{{}} + +{{}} +{ "foo": 1, "bar": 2, "extra": true } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "required": [ "name", "age" ], + "properties": { + "name": { "type": "string" }, + "age": { "type": "integer" } + } +} +{{}} + +{{}} +{ "name": "John Doe", "age": 30 } +{{}} + +{{}} +{ "name": "John Doe", "age": 30, "extra": true } +{{}} + +{{}} +{ "name": "John Doe" } +{{}} + +{{}} +{ "name": 123, "age": "foo" } +{{}} + +{{}} +{} +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/then.markdown b/content/draft7/validation/then.markdown index 8d01f629..1d916038 100644 --- a/content/draft7/validation/then.markdown +++ b/content/draft7/validation/then.markdown @@ -27,3 +27,64 @@ related: - vocabulary: validation keyword: not --- + +The [`then`]({{< ref "draft7/validation/then" >}}) keyword restricts instances +to validate against the given subschema if the [`if`]({{< ref +"draft7/validation/if" >}}) sibling keyword successfully validated against the +instance. + +{{}} This keyword has no effect if the [`if`]({{< ref "draft7/validation/if" >}}) keyword is not declared within the same +subschema. {{}} + +{{}} The [`if`]({{< ref "draft7/validation/if" >}}), +[`then`]({{< ref "draft7/validation/then" >}}), and [`else`]({{< ref "draft7/validation/else" >}}) keywords can be thought of as imperative variants +of the [`anyOf`]({{< ref "draft7/validation/anyof" >}}) keyword, and both +approaches are equally capable of describing arbitrary conditions. Choose the +one that more elegantly describes your desired +constraints.{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": { "multipleOf": 2 }, + "then": { "minimum": 0 } +} +{{}} + +{{}} +10 +{{}} + +{{}} +-2 +{{}} + +{{}} +7 +{{}} + +{{}} +-3 +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": { "multipleOf": 2 }, + "then": { "title": "The value is an even number" } +} +{{}} + +{{}} +10 +{{}} + +{{}} +5 +{{}} diff --git a/content/draft7/validation/title.markdown b/content/draft7/validation/title.markdown index 621432d4..af13052a 100644 --- a/content/draft7/validation/title.markdown +++ b/content/draft7/validation/title.markdown @@ -21,3 +21,66 @@ related: - vocabulary: validation keyword: writeOnly --- + +The [`title`]({{< ref "draft7/validation/title" >}}) keyword is a placeholder +for a concise human-readable string summary of what a schema or any of its +subschemas are about. This keyword is merely descriptive and does not affect +validation. + +{{}} + +We heavily recommend to declare this keyword at the top level of every schema, +as a human-readable introduction to what the schema is about. + +When doing so, note that the JSON Schema specification does not impose or +recommend a maximum length for this keyword. However, it is common practice to +stick to [Git commit message +title](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) +conventions and set it to a capitalised string of *50 characters or less*. If +you run out of space, you can move the additional information to the +[`description`]({{< ref "draft7/validation/description" >}}) keyword. + +{{}} + + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Even Number", + "type": "number", + "multipleOf": 2 +} +{{}} + +{{}} +10 +{{}} + +{{}} +7 +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Number", + "type": "number", + "if": { "multipleOf": 2 }, + "then": { "title": "Even Number" }, + "else": { "title": "Odd Number" } +} +{{}} + +{{}} +10 +{{}} + +{{}} +7 +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/type.markdown b/content/draft7/validation/type.markdown index 4906284a..60a2d63d 100644 --- a/content/draft7/validation/type.markdown +++ b/content/draft7/validation/type.markdown @@ -17,3 +17,120 @@ changed_in: - draft6 - draft4 --- + +The supported types are the following. Note that while the [ECMA +404](https://ecma-international.org/publications-and-standards/standards/ecma-404/) +JSON standard defines the JSON grammar without mention of encodings, the [IETF +RFC 8259](https://www.rfc-editor.org/rfc/rfc8259) JSON standard provides +specific guidance for JSON numbers and JSON strings which are documented in the +*Interoperable Encoding* column. Other encodings will likely not be accepted by +JSON parsers. + +| Type | Description | Interoperable Encoding | +|-------------|------------------------------------------|----------------------------------------------------------------------------------------------------------| +| `"null"` | The JSON null constant | N/A | +| `"boolean"` | The JSON true or false constants | N/A | +| `"object"` | A JSON object | N/A | +| `"array"` | A JSON array | N/A | +| `"number"` | A JSON number | [IEEE 764](https://ieeexplore.ieee.org/document/8766229) 64-bit double-precision floating point encoding (except `NaN`, `Infinity`, and `+0`) | +| `"integer"` | A JSON number that represents an integer | 64-bit signed integer encoding (from `-(2^53)+1` to `(2^53)-1`) | +| `"string"` | A JSON string | [UTF-8](https://en.wikipedia.org/wiki/UTF-8) Unicode encoding | + +Note that while the JSON grammar does not distinguish between integer and real +numbers, JSON Schema provides the [`integer`]({{< ref "draft7/validation/type" >}}) logical type that matches either integers (such +as `2`), or real numbers where the fractional part is zero (such as `2.0`). +Additionally, numeric constructs inherent to floating point encodings (like +`NaN` and `Infinity`) are not permitted in JSON. However, the negative zero +(`-0`) is permitted. + +{{}} To avoid interoperability issues, do not produce JSON +documents with numbers that exceed the [IETF RFC +8259](https://www.rfc-editor.org/rfc/rfc8259) limits described in the +*Interoperable Encodings* column of the table above. + +If more numeric precision is required, consider representing numbers as JSON +strings or as multiple numbers. For example, fixed-precision real numbers can +be represented as an array of two integers for the integral and fractional +components.{{}} + +{{}} The JavaScript programming language (and by extension +languages such as TypeScript) represent all numbers, including integers, using +the [IEEE 764](https://ieeexplore.ieee.org/document/8766229) floating-point +encoding. As a result, parsing JSON documents with integers beyond the 53-bit +range is prone to precision problems. Read [How numbers are encoded in +JavaScript](https://2ality.com/2012/04/number-encoding.html) by Dr. Axel +Rauschmayer for a more detailed overview of JavaScript's numeric +limitations.{{}} + +{{}}JSON allows numbers to be represented in [scientific +exponential +notation](https://en.wikipedia.org/wiki/Scientific_notation#E_notation). For +example, numbers like `1.0e+28` (equivalent to 10000000000000000000000000000.0) +are valid according to the JSON grammar. This notation is convenient for +expressing long numbers. However, be careful with not accidentally exceeding +the interoperable limits described by the [IETF RFC +8259](https://www.rfc-editor.org/rfc/rfc8259) JSON +standard.{{}} + +## Examples + +{{< schema "A schema that describes numeric instances" >}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "number" +} +{{< /schema >}} + +{{< instance-pass "An integer is valid" >}} +42 +{{< /instance-pass >}} + +{{< instance-pass "A real number is valid" >}} +3.14 +{{< /instance-pass >}} + +{{< instance-pass "A number in scientific exponential notation is valid" >}} +1.0e+28 +{{< /instance-pass >}} + +{{< instance-fail "A string is not valid" >}} +"foo" +{{< /instance-fail >}} + +{{< schema "A schema that describes boolean or array instances" >}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": [ "boolean", "array" ] +} +{{< /schema >}} + +{{< instance-pass "The true boolean is valid" >}} +true +{{< /instance-pass >}} + +{{< instance-fail "A number is invalid" >}} +1234 +{{< /instance-fail >}} + +{{< instance-pass "An arbitrary array is valid" >}} +[ 1, 2, 3 ] +{{< /instance-pass >}} + +{{< schema "A schema that describes integer instances" >}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "integer" +} +{{< /schema >}} + +{{< instance-pass "An integer is valid" >}} +42 +{{< /instance-pass >}} + +{{< instance-pass "A real number with a zero fractional part is valid" >}} +3.0 +{{< /instance-pass >}} + +{{< instance-fail "A real number with a non-zero fractional part is invalid" >}} +3.14 +{{< /instance-fail >}} diff --git a/content/draft7/validation/uniqueItems.markdown b/content/draft7/validation/uniqueItems.markdown index cf68e132..1c3667f7 100644 --- a/content/draft7/validation/uniqueItems.markdown +++ b/content/draft7/validation/uniqueItems.markdown @@ -21,3 +21,64 @@ related: - vocabulary: validation keyword: contains --- + +When set to `true`, the [`uniqueItems`]({{< ref "draft7/validation/uniqueitems" >}}) keyword restricts array instances to +items that only occur once in the array. Note that empty arrays and arrays that +consist of a single item satisfy uniqueness by definition. + +{{}} Keep in mind that depending on the size and complexity of +arrays, this keyword may introduce significant validation overhead. The paper +[JSON: data model, query languages and schema +specification](https://arxiv.org/abs/1701.02221) also noted how the presence of +this keyword can negatively impact satisfiability analysis of +schemas.{{}} + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "uniqueItems": true +} +{{}} + +{{}} +[ 1, "hello", true, { "name": "John" } ] +{{}} + +{{}} +[ { "name": "John" }, 1, "hello", true, { "name": "John" } ] +{{}} + +{{}} +[] +{{}} + +{{}} +"Hello World" +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "uniqueItems": false +} +{{}} + +{{}} +[ 1, "hello", true, { "name": "John" } ] +{{}} + +{{}} +[ { "name": "John" }, 1, "hello", true, { "name": "John" } ] +{{}} + +{{}} +[] +{{}} + +{{}} +"Hello World" +{{}} diff --git a/content/draft7/validation/writeOnly.markdown b/content/draft7/validation/writeOnly.markdown index b4489898..2d8d0ad6 100644 --- a/content/draft7/validation/writeOnly.markdown +++ b/content/draft7/validation/writeOnly.markdown @@ -23,3 +23,90 @@ related: - vocabulary: validation keyword: default --- + +The [`writeOnly`]({{< ref "draft7/validation/writeonly" >}}) keyword, when set +to `true`, signifies that an instance value (such as a specific object +property) can be modified or removed but not read, whatever that means in the +context of the system. For example, form generators may rely on this keyword to +mark the corresponding input as as a password field. This keyword provides +metadata for documentation purposes and does not affect validation. + +{{}} + +Avoid setting this keyword to the default value `false`. If an instance value +is not considered to be write only, the best practice is to omit the use of +this keyword altogether. + +Also avoid simultaneously setting this keyword and the [`readOnly`]({{< ref "draft7/validation/readonly" >}}) keyword to `true` for the same instance +location, resulting in ambiguous semantics. + +{{}} + +{{}} + +Tooling makers must be careful when statically traversing schemas in search of +occurrences of this keyword. It is possible for schemas to make use of this +keyword behind conditional operators, references, or any other type of keyword +that makes it hard or even impossible to correctly locate these values in all +cases. + +For example, an instance property might only be write only under certain +conditions determined by a dynamic operator like [`anyOf`]({{< ref +"draft7/validation/anyof" >}}). + +{{}} + +## Examples + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "username": { "type": "string" }, + "password": { "type": "string", "writeOnly": true } + } +} +{{}} + +{{}} +{ "username": "jviotti", "password": "mysupersecretpassword" } +{{}} + +{{}} +{ "username": "jviotti" } +{{}} + +{{}} +{ "password": null } +{{}} + +{{}} +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "username": { "type": "string" }, + "password": { "type": "string" } + }, + "dependencies": { + "username": { + "properties": { "password": { "writeOnly": true } } + } + } +} +{{}} + +{{}} +{ "username": "jviotti", "password": "mysupersecretpassword" } +{{}} + +{{}} +{ "username": "jviotti" } +{{}} + +{{}} +{ "password": "mysupersecretpassword" } +{{}} + +{{}} +{ "password": null } +{{}}