Skip to content

Commit

Permalink
Merge pull request #1428 from ajv-validator/jtd
Browse files Browse the repository at this point in the history
JSON Type Definition
  • Loading branch information
epoberezkin authored Feb 10, 2021
2 parents 3372277 + 078d6a8 commit 1996f6b
Show file tree
Hide file tree
Showing 49 changed files with 1,532 additions and 171 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "spec/JSON-Schema-Test-Suite"]
path = spec/JSON-Schema-Test-Suite
url = https://github.com/json-schema/JSON-Schema-Test-Suite.git
[submodule "spec/json-typedef-spec"]
path = spec/json-typedef-spec
url = https://github.com/jsontypedef/json-typedef-spec.git
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
spec/JSON-Schema-Test-Suite
spec/json-typedef-spec
.browser
coverage
dist
Expand Down
103 changes: 97 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<img align="right" alt="Ajv logo" width="160" src="https://ajv.js.org/images/ajv_logo.png">

# Ajv: Another JSON Schema Validator
# Ajv: Another JSON schema validator

The fastest JSON Schema validator for Node.js and browser. Supports draft-06/07/2019-09 (draft-04 is supported in [version 6](https://github.com/ajv-validator/ajv/tree/v6)).
The fastest JSON schema validator for Node.js and browser. Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](https://github.com/ajv-validator/ajv/tree/v6)) and JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/).

[![build](https://github.com/ajv-validator/ajv/workflows/build/badge.svg)](https://github.com/ajv-validator/ajv/actions?query=workflow%3Abuild)
[![npm](https://img.shields.io/npm/v/ajv.svg)](https://www.npmjs.com/package/ajv)
Expand All @@ -17,9 +17,10 @@ The fastest JSON Schema validator for Node.js and browser. Supports draft-06/07/

## Using version 7

Ajv version 7 is released with these changes:
Ajv version 7 has these new features:

- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/validation.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09).
- NEW: support of JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) (from [v7.1.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v7.1.0))
- to reduce the mistakes in JSON schemas and unexpected validation results, [strict mode](./docs/strict-mode.md) is added - it prohibits ignored or ambiguous JSON Schema elements.
- to make code injection from untrusted schemas impossible, [code generation](./docs/codegen.md) is fully re-written to be safe and to allow code optimization (compiled schema code size is reduced by more than 10%).
- to simplify Ajv extensions, the new keyword API that is used by pre-defined keywords is available to user-defined keywords - it is much easier to define any keywords now, especially with subschemas. [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package was updated to use the new API (in [v4.0.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v4.0.0))
Expand Down Expand Up @@ -71,6 +72,9 @@ Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components]
- [Performance](#performance)
- [Features](#features)
- [Getting started](#usage)
- [Choosing schema language](#choosing-schema-language)
- [JSON Schema](#json-schema)
- [JSON Type Definition](#json-type-definition)
- [Frequently Asked Questions](./docs/faq.md)
- [Using in browser](#using-in-browser)
- [Content Security Policy](./docs/security.md#content-security-policy)
Expand Down Expand Up @@ -166,14 +170,18 @@ Performance of different validators by [json-schema-benchmark](https://github.co

## Features

- Ajv implements full JSON Schema [draft-06/07](http://json-schema.org/) standards (draft-04 is supported in v6):
- Ajv implements JSON Schema [draft-06/07/2019-09](http://json-schema.org/) standards (draft-04 is supported in v6):
- all validation keywords (see [JSON Schema validation keywords](./docs/json-schema.md))
- keyword "nullable" from [Open API 3 specification](https://swagger.io/docs/specification/data-models/data-types/).
- full support of remote references (remote schemas have to be added with `addSchema` or compiled to be available)
- support of circular references between schemas
- correct string lengths for strings with unicode pairs
- [formats](#formats) defined by JSON Schema draft-07 standard (with [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin) and additional formats (can be turned off)
- [validates schemas against meta-schema](./docs/api.md#api-validateschema)
- NEW: supports [JSON Type Definition](https://datatracker.ietf.org/doc/rfc8927/):
- all forms (see [JSON Type Definition schema forms](./docs/json-type-definition.md))
- meta-schema for JTD schemas
- "union" keyword and user-defined keywords (can be used inside "metadata" member of the schema)
- supports [browsers](#using-in-browser) and Node.js 0.10-14.x
- [asynchronous loading](./docs/validation.md#asynchronous-schema-compilation) of referenced schemas during compilation
- "All errors" validation mode with [option allErrors](./docs/api.md#options)
Expand Down Expand Up @@ -262,6 +270,26 @@ if (validate(data)) {
}
```

With JSON Type Definition schema:

```javascript
const Ajv = require("ajv").default

const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
properties: {
foo: {type: "float64"},
},
}
const validate = ajv.compile(schema)
const valid = validate({foo: 1}) // true
if (!valid) console.log(validate.errors)
// Unlike JSON Schema:
const valid1 = validate(1) // false, bot an object
const valid2 = validate({}) // false, foo is required
const valid3 = validate({foo: 1, bar: 2}) // false, bar is additional
```

See [this test](./spec/types/json-schema.spec.ts) for an advanced example, [API reference](./docs/api.md) and [Options](./docs/api.md#options) for more details.

Ajv compiles schemas to functions and caches them in all cases (using schema itself as a key for Map) or another function passed via options), so that the next time the same schema is used (not necessarily the same object instance) it won't be compiled again.
Expand Down Expand Up @@ -290,7 +318,7 @@ Then you need to load Ajv with support of JSON Schema draft-07 in the browser:
</script>
```

or to load the bundle that supports JSONSchema draft-2019-09:
To load the bundle that supports JSON Schema draft-2019-09:

```html
<script src="bundle/ajv2019.min.js"></script>
Expand All @@ -302,12 +330,75 @@ or to load the bundle that supports JSONSchema draft-2019-09:
</script>
```

To load the bundle that supports JSON Type Definition:

```html
<script src="bundle/ajvJTD.min.js"></script>
<script>
;(function () {
const Ajv = window.ajvJTD.default
const ajv = new Ajv()
})()
</script>
```

This bundle can be used with different module systems; it creates global `ajv` (or `ajv2019`) if no module system is found.

The browser bundle is available on [cdnjs](https://cdnjs.com/libraries/ajv).

**Please note**: some frameworks, e.g. Dojo, may redefine global require in a way that is not compatible with CommonJS module format. In this case Ajv bundle has to be loaded before the framework and then you can use global `ajv` (see issue [#234](https://github.com/ajv-validator/ajv/issues/234)).

## Choosing schema language

Both JSON Schema and JSON Type Definition are cross-platform specifications with implementations in multiple programming languages that help you define the shape and requirements to your JSON data.

This section compares their pros/cons to help decide which specification fits your application better.

### 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 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)
- Can be effectively used for validation of any JavaScript objects and configuration files.
- Cons
- Defines the collection of restrictions on the data, rather than the shape of the data.
- No standard support for tagged unions.
- 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
- dynamic recursive references
- Internet draft status (rather than RFC)

See [JSON Schema](./docs/json-schema.md) for the list of defined keywords.

### JSON Type Definition

- Pros:
- Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types.
- 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 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 from multiple files in the application code.

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

## Using in ES5 environment

You need to:
Expand All @@ -334,7 +425,7 @@ CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-vali
- user-defined meta-schemas, validation keywords and formats
- files in JSON, JSON5, YAML, and JavaScript format
- all Ajv options
- reporting changes in data after validation in [JSON-patch](https://tools.ietf.org/html/rfc6902) format
- reporting changes in data after validation in [JSON-patch](https://datatracker.ietf.org/doc/rfc6902/) format

## Extending Ajv

Expand Down
47 changes: 32 additions & 15 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,36 +251,37 @@ Option defaults:
const defaultOptions = {
// strict mode options (NEW)
strict: true,
strictTypes: "log",
strictTuples: "log",
allowUnionTypes: false,
allowMatchingProperties: false,
validateFormats: true,
strictTypes: "log", // *
strictTuples: "log", // *
allowUnionTypes: false, // *
allowMatchingProperties: false, // *
validateFormats: true, // *
// validation and reporting options:
$data: false,
$data: false, // *
allErrors: false,
verbose: false,
$comment: false,
verbose: false, // *
$comment: false, // *
formats: {},
keywords: {},
schemas: {},
logger: undefined,
loadSchema: undefined, // function(uri: string): Promise {}
loadSchema: undefined, // *, function(uri: string): Promise {}
// options to modify validated data:
removeAdditional: false,
useDefaults: false,
coerceTypes: false,
useDefaults: false, // *
coerceTypes: false, // *
// advanced options:
meta: true,
validateSchema: true,
addUsedSchema: true,
inlineRefs: true,
passContext: false,
loopRequired: Infinity,
loopRequired: Infinity, // *
loopEnum: Infinity, // NEW
ownProperties: false,
multipleOfPrecision: undefined,
messages: true,
multipleOfPrecision: undefined, // *
messages: true, // false with JTD
ajvErrors: false // only with JTD
code: {
// NEW
es5: false,
Expand All @@ -292,6 +293,8 @@ const defaultOptions = {
}
```

<sup>\*</sup> these options are not supported with JSON Type Definition schemas

#### Strict mode options (NEW in v7)

- _strict_: By default Ajv executes in strict mode, that is designed to prevent any unexpected behaviours or silently ignored mistakes in schemas (see [Strict Mode](./strict-mode.md) for more details). It does not change any validation results, but it makes some schemas invalid that would be otherwise valid according to JSON Schema specification. Option values:
Expand Down Expand Up @@ -363,6 +366,7 @@ const defaultOptions = {
- _ownProperties_: by default Ajv iterates over all enumerable object properties; when this option is `true` only own enumerable object properties (i.e. found directly on the object rather than on its prototype) are iterated. Contributed by @mbroadst.
- _multipleOfPrecision_: by default `multipleOf` keyword is validated by comparing the result of division with parseInt() of that result. It works for dividers that are bigger than 1. For small dividers such as 0.01 the result of the division is usually not integer (even when it should be integer, see issue [#84](https://github.com/ajv-validator/ajv/issues/84)). If you need to use fractional dividers set this option to some positive integer N to have `multipleOf` validated using this formula: `Math.abs(Math.round(division) - division) < 1e-N` (it is slower but allows for float arithmetic deviations).
- _messages_: Include human-readable messages in errors. `true` by default. `false` can be passed when messages are generated outside of Ajv code (e.g. with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n)).
- _ajvErrors_: this option is only supported with JTD schemas to generate error objects with the properties described in the first part of [Validation errors](#validation-errors) section, otherwise JTD errors are generated when JTD schemas are used (see the second part of [the same section](#validation-errors)).
- _code_ (new in v7): code generation options:

```typescript
Expand Down Expand Up @@ -393,7 +397,7 @@ In case of validation failure, Ajv assigns the array of errors to `errors` prope
### Error objects
Each error is an object with the following properties:
Each error reported when validating against JSON Schema (also when validating against JTD schema with option `ajvErrors`) is an object with the following properties:
```typescript
interface ErrorObject {
Expand All @@ -413,6 +417,19 @@ interface ErrorObject {
}
```

[JTD specification](./json-type-definition.md) defines strict format for validation errors, where each error is an object with the following properties:

```typescript
interface JTDErrorObject {
instancePath: string // JSON Pointer to the location in the data instance
schemaPath: string // JSON Pointer to the location in the schema
}
```

This error format is used when using JTD schemas. To simplify usage, you may still generate Ajv error objects using `ajvErrors` option. You can also add a human-readable error message to error objects using option `messages`.

**Please note**: Ajv is not fully consistent with JTD regarding the error objects in some scenarios - it will be consistent by the time Ajv version 8 is released. Therefore it is not recommended yet to use error objects for any advanced application logic.

### Error parameters

Properties of `params` object in errors depend on the keyword that failed validation.
Expand Down
Loading

0 comments on commit 1996f6b

Please sign in to comment.