Skip to content

Commit

Permalink
JTD docs
Browse files Browse the repository at this point in the history
  • Loading branch information
epoberezkin committed Feb 8, 2021
1 parent 9737aaa commit 5ddef2e
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 36 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,23 +357,23 @@ This section compares their pros/cons to help decide which specification fits yo
### JSON Schema

- Pros
- Wide specification adoption.
- Used as part of OpenAPI specification.
- Support of complex validation scenarios:
- untagged unions and boolean logic
- conditional schemas and dependencies
- restrictions on number ranges and string, array and object sizes
- restrictions on the number ranges and the size of strings, arrays and objects
- semantic validation with formats, patterns and content keywords
- distribute strict record definitions across multiple schemas (with unevaluatedProperties)
- Wide specification adoption.
- Used as part of OpenAPI specification.
- Can be effectively used for validation of any JavaScript objects and configuration files.
- Cons
- Defines the collection of restrictions on your data, rather than the shape of the data.
- Defines the collection of restrictions on the data, rather than the shape of the data.
- No standard support for tagged unions.
- Complex, error prone and often confusing for the new users (Ajv has [strict mode](./docs/strict-mode) to compensate for it, but it is not cross-platform).
- Some parts of specification are difficult to implement, creating the risk of divergence of implementations:
- Complex and error prone for the new users (Ajv has [strict mode](./docs/strict-mode) to compensate for it, but it is not cross-platform).
- Some parts of specification are difficult to implement, creating the risk of implementations divergence:
- reference resolution model
- unevaluatedProperties/unevaluatedItems
- recursive references
- dynamic recursive references
- Internet draft status (rather than RFC)

See [JSON Schema](./docs/json-schema.md) for the list of defined keywords.
Expand All @@ -382,20 +382,20 @@ See [JSON Schema](./docs/json-schema.md) for the list of defined keywords.

- Pros:
- Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types.
- Extremely simple, enforcing best practices for cross-platform JSON API modelling.
- Very simple, enforcing the best practices for cross-platform JSON API modelling.
- Simple to implement, ensuring consistency across implementations.
- Defines the shape of JSON data via strictly defined schema forms (rather than the collection of restrictions).
- Effective support for tagged unions.
- Designed to protect against user mistakes.
- Approved as [RFC8927](https://datatracker.ietf.org/doc/rfc8927/)
- Cons:
- Limited, compared with JSON Schema - no untagged unions<sup>\*</sup>, conditionals, references between schemas<sup>\*\*</sup>, etc.
- Limited, compared with JSON Schema - no support for untagged unions<sup>\*</sup>, conditionals, references between different schema files<sup>\*\*</sup>, etc.
- No meta-schema in the specification<sup>\*</sup>.
- Brand new - limited industry adoption (as of January 2021).

<sup>\*</sup> Ajv defines meta-schema for JTD schemas and non-standard keyword "union" that can be used inside "metadata" object.

<sup>\*\*</sup> You can still combine schemas in JavaScript code.
<sup>\*\*</sup> You can still combine schemas from multiple files in the application code.

See [JSON Type Definition](./docs/json-type-definition.md) for the list of defined schema forms.

Expand Down
65 changes: 56 additions & 9 deletions docs/json-type-definition.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
# JSON Type Definition

This document informally describes JSON Type Definitions specification to help Ajv users to start using it. For formal definition please refer to [RFC8927](https://datatracker.ietf.org/doc/rfc8927/). Please report any contradictions in this document with the specification.
This document informally describes JSON Type Definition (JTD) specification to help Ajv users to start using it. For formal definition please refer to [RFC8927](https://datatracker.ietf.org/doc/rfc8927/). Please report any contradictions in this document with the specification.

## Contents

- [JTD schema forms](#jtd-schema-forms):
- [type](#type-schema-form) (for primitive values)
- [enum](#enum-schema-form)
- [elements](#elements-schema-form) (for arrays)
- [properties](#properties-schema-form) (for records)
- [discriminator](#discriminator-schema-form) (for tagged union of records)
- [values](#values-schema-form) (for dictionary)
- [ref](#ref-schema-form) (to reference a schema in definitions)
- [empty](#empty-schema-form) (for any data)
- [Extending JTD](#extending-jtd)
- [metadata](#metadata-schema-member)
- [union](#union-keyword)
- [user-defined keywords](#user-defined-keywords)

## JTD schema forms

JTD specification defines 8 different forms that the schema for JSON can take for one of most widely used data types in JSON messages (API requests and responses).

Expand All @@ -13,7 +31,7 @@ All forms require that:

Root schema can have member `definitions` that has a dictionary of schemas that can be references from any other schemas using form `ref`

## Type schema form
### Type schema form

This form defines a primitive value.

Expand Down Expand Up @@ -45,7 +63,7 @@ Unlike JSON Schema, JTD does not allow defining values that can take one of seve
}
```

## Enum schema form
### Enum schema form

This form defines a string that can take one of the values from the list (the values in the list must be unique).

Expand All @@ -61,7 +79,7 @@ Unlike JSON Schema, JTD does not allow defining `enum` with values of any other
}
```

## Elements schema form
### Elements schema form

This form defines a homogenous array of any size (possibly empty) with the elements that satisfy a given schema.

Expand All @@ -85,7 +103,7 @@ Valid data: `[]`, `["foo"]`, `["foo", "bar"]`

Invalid data: `["foo", 1]`, any type other than array

## Properties schema form
### Properties schema form

This form defines record (JSON object) that has defined required and optional properties.

Expand Down Expand Up @@ -144,7 +162,7 @@ Invalid data: `{}`, `{foo: 1}`, `{foo: "bar", bar: "3"}`, any type other than ob
}
```

## Discriminator schema form
### Discriminator schema form

This form defines discriminated (tagged) union of different record types.

Expand Down Expand Up @@ -202,7 +220,7 @@ Invalid data: `{}`, `{foo: "1"}`, `{version: 1, foo: "1"}`, any type other than
}
```

## Values schema form
### Values schema form

This form defines a homogenous dictionary where the values of members satisfy a given schema.

Expand All @@ -226,7 +244,7 @@ Valid data: `{}`, `{"foo": 1}`, `{"foo": 1, "bar": 2}`

Invalid data: `{"foo": "bar"}`, any type other than object

## Ref schema form
### Ref schema form

This form defines a reference to the schema that is present in the corresponding key in the `definitions` member of the root schema.

Expand Down Expand Up @@ -281,6 +299,35 @@ Unlike JSON Schema, JTD does not allow to reference:
}
```

## Empty schema form
### Empty schema form

Empty JTD schema defines the data instance that can be of any type, including JSON `null` (even if `nullable` member is not present). It cannot have any member other than `nullable` and `metadata`.

## Extending JTD

### Metadata schema member

Each schema form may have an optional member `metadata` that JTD reserves for implementation/application specific extensions. Ajv uses this member as a location where any non-standard keywords can be used, such as:
- `union` keyword included in Ajv
- any user-defined keywords, for example keywords defined in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package
- JSON Schema keywords, as long as their names are different from standard JTD keywords. It can be used to enable a gradual migration from JSON Schema to JTD, should it be required.

**Please note**: Ajv-specific extension to JTD are likely to be unsupported by other tools, so while it may simplify adoption, it undermines the cross-platform objective of using JTD. While it is ok to put some human readable information in `metadata` member, it is recommended not to add any validation logic there (even if it is supported by Ajv).

Additional restrictions that Ajv enforces on `metadata` schema member:
- you cannot use standard JTD keywords there. While strictly speaking it is allowed by the specification, these keywords should be ignored inside `metadata` - the general approach of Ajv is to avoid anything that is ignored.
- you need to define all members used in `metadata` as keywords. If they are no-op it can be done with `ajv.addKeyword("my-metadata-keyword")`. This restriction can be removed by disabling [strict mode](https://github.com/ajv-validator/ajv/blob/master/docs/strict-mode.md), without affecting the strictness of JTD - unknown keywords would still be prohibited in the schema itself.

### Union keyword

Ajv defines `union` keyword that is used in the schema that validates JTD schemas ([meta-schema](../lib/refs/jtd-schema.ts)).

This keyword can be used only inside `metadata` schema member.

**Please note**: This keyword is non-standard and it is not supported in other JTD tools, so it is recommended NOT to use this keyword in schemas for your data if you want them to be cross-platform.

### User-defined keywords

Any user-defined keywords that can be used in JSON Schema schemas can also be used in JTD schemas, including the keywords in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package.

**Please note**: It is strongly recommended to only use it to simplify migration from JSON Schema to JTD and not to use non-standard keywords in the new schemas, as these keywords are not supported by any other tools.
52 changes: 35 additions & 17 deletions docs/strict-mode.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
## Strict mode
# Strict mode

Strict mode intends to prevent any unexpected behaviours or silently ignored mistakes in user schemas. It does not change any validation results compared with JSON Schema specification, but it makes some schemas invalid and throws exception or logs warning (with `strict: "log"` option) in case any restriction is violated.
Strict mode intends to prevent any unexpected behaviours or silently ignored mistakes in user schemas. It does not change any validation results compared with the specification, but it makes some schemas invalid and throws exception or logs warning (with `strict: "log"` option) in case any restriction is violated.

To disable all strict mode restrictions use option `strict: false`. Some of the restrictions can be changed with their own options

- [Prohibit ignored keywords](#prohibit-ignored-keywords)
- unknown keywords
- ignored "additionalItems" keyword
- ignored "if", "then", "else" keywords
- ignored "contains", "maxContains" and "minContains" keywords
- unknown formats
- ignored defaults
- [Prevent unexpected validation](#prevent-unexpected-validation)
- overlap between "properties" and "patternProperties" keywords (also `allowMatchingProperties` option)
- unconstrained tuples (also `strictTuples` option)
- [Strict types](#strict-types) (also `strictTypes` option)
- union types (also `allowUnionTypes` option)
- contradictory types
- require applicable types
- [Strict number validation](#strict-number-validation)
- [JSON Type Definition schemas](#json-type-definition-schemas)
- [JSON Schema schemas](#json-schema-schemas)
- [Prohibit ignored keywords](#prohibit-ignored-keywords)
- unknown keywords
- ignored "additionalItems" keyword
- ignored "if", "then", "else" keywords
- ignored "contains", "maxContains" and "minContains" keywords
- unknown formats
- ignored defaults
- [Prevent unexpected validation](#prevent-unexpected-validation)
- overlap between "properties" and "patternProperties" keywords (also `allowMatchingProperties` option)
- unconstrained tuples (also `strictTuples` option)
- [Strict types](#strict-types) (also `strictTypes` option)
- union types (also `allowUnionTypes` option)
- contradictory types
- require applicable types
- [Strict number validation](#strict-number-validation)

## JSON Type Definition schemas

JTD specification is strict - whether Ajv strict mode is enabled or not it will not allow schemas with ignored or ambiguous elements, including:
- unknown schema keywords
- combining multiple schema forms in one schema
- defining the same property as both required and optional
- re-defining discriminator tag inside properties, even if the definition is non-contradictory

See [JSON Type Definition](./json-type-definition.md) for informal and [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) for formal specification descriptions.

The only change that strict mode introduces to JTD schemas, without changing their syntax or semantics, is the requirement that all members that are present in optional `metadata` members are defined as Ajv keywords. This restriction can be disabled with `strict: false` option, without any impact to other JTD features.

## JSON Schema schemas

JSON Schema specification is very permissive and allows many elements in the schema to be quietly ignored or be ambiguous. It is recommended to use JSON Schema with strict mode.

### Prohibit ignored keywords

Expand Down

0 comments on commit 5ddef2e

Please sign in to comment.