3 Custom JSON-Schema keywords for [Ajv](https://github.com/epoberezkin/ajv) validator
5 [![Build Status](https://travis-ci.org/ajv-validator/ajv-keywords.svg?branch=master)](https://travis-ci.org/ajv-validator/ajv-keywords)
6 [![npm](https://img.shields.io/npm/v/ajv-keywords.svg)](https://www.npmjs.com/package/ajv-keywords)
7 [![npm downloads](https://img.shields.io/npm/dm/ajv-keywords.svg)](https://www.npmjs.com/package/ajv-keywords)
8 [![Coverage Status](https://coveralls.io/repos/github/ajv-validator/ajv-keywords/badge.svg?branch=master)](https://coveralls.io/github/ajv-validator/ajv-keywords?branch=master)
9 [![Dependabot](https://api.dependabot.com/badges/status?host=github&repo=ajv-validator/ajv-keywords)](https://app.dependabot.com/accounts/ajv-validator/repos/60477053)
10 [![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv)
17 - [Keywords](#keywords)
20 - [instanceof](#instanceof)
21 - [Keywords for numbers](#keywords-for-numbers)
22 - [range and exclusiveRange](#range-and-exclusiverange)
23 - [Keywords for strings](#keywords-for-strings)
25 - [formatMaximum / formatMinimum and formatExclusiveMaximum / formatExclusiveMinimum](#formatmaximum--formatminimum-and-formatexclusivemaximum--formatexclusiveminimum)
26 - [transform](#transform)<sup>\*</sup>
27 - [Keywords for arrays](#keywords-for-arrays)
28 - [uniqueItemProperties](#uniqueitemproperties)
29 - [Keywords for objects](#keywords-for-objects)
30 - [allRequired](#allrequired)
31 - [anyRequired](#anyrequired)
32 - [oneRequired](#onerequired)
33 - [patternRequired](#patternrequired)
34 - [prohibited](#prohibited)
35 - [deepProperties](#deepproperties)
36 - [deepRequired](#deeprequired)
37 - [Compound keywords](#compound-keywords)
38 - [switch](#switch) (deprecated)
39 - [select/selectCases/selectDefault](#selectselectcasesselectdefault) (BETA)
40 - [Keywords for all types](#keywords-for-all-types)
41 - [dynamicDefaults](#dynamicdefaults)<sup>\*</sup>
42 - [Security contact](#security-contact)
43 - [Open-source software support](#open-source-software-support)
46 <sup>\*</sup> - keywords that modify data
52 npm install ajv-keywords
58 To add all available keywords:
61 var Ajv = require('ajv');
63 require('ajv-keywords')(ajv);
65 ajv.validate({ instanceof: 'RegExp' }, /.*/); // true
66 ajv.validate({ instanceof: 'RegExp' }, '.*'); // false
69 To add a single keyword:
72 require('ajv-keywords')(ajv, 'instanceof');
75 To add multiple keywords:
78 require('ajv-keywords')(ajv, ['typeof', 'instanceof']);
81 To add a single keyword in browser (to avoid adding unused code):
84 require('ajv-keywords/keywords/instanceof')(ajv);
94 Based on JavaScript `typeof` operation.
96 The value of the keyword should be a string (`"undefined"`, `"string"`, `"number"`, `"object"`, `"function"`, `"boolean"` or `"symbol"`) or array of strings.
98 To pass validation the result of `typeof` operation on the value should be equal to the string (or one of the strings in the array).
101 ajv.validate({ typeof: 'undefined' }, undefined); // true
102 ajv.validate({ typeof: 'undefined' }, null); // false
103 ajv.validate({ typeof: ['undefined', 'object'] }, null); // true
109 Based on JavaScript `instanceof` operation.
111 The value of the keyword should be a string (`"Object"`, `"Array"`, `"Function"`, `"Number"`, `"String"`, `"Date"`, `"RegExp"`, `"Promise"` or `"Buffer"`) or array of strings.
113 To pass validation the result of `data instanceof ...` operation on the value should be true:
116 ajv.validate({ instanceof: 'Array' }, []); // true
117 ajv.validate({ instanceof: 'Array' }, {}); // false
118 ajv.validate({ instanceof: ['Array', 'Function'] }, function(){}); // true
121 You can add your own constructor function to be recognised by this keyword:
124 function MyClass() {}
125 var instanceofDefinition = require('ajv-keywords').get('instanceof').definition;
126 // or require('ajv-keywords/keywords/instanceof').definition;
127 instanceofDefinition.CONSTRUCTORS.MyClass = MyClass;
129 ajv.validate({ instanceof: 'MyClass' }, new MyClass); // true
133 ### Keywords for numbers
135 #### `range` and `exclusiveRange`
137 Syntax sugar for the combination of minimum and maximum keywords, also fails schema compilation if there are no numbers in the range.
139 The value of this keyword must be the array consisting of two numbers, the second must be greater or equal than the first one.
141 If the validated value is not a number the validation passes, otherwise to pass validation the value should be greater (or equal) than the first number and smaller (or equal) than the second number in the array. If `exclusiveRange` keyword is present in the same schema and its value is true, the validated value must not be equal to the range boundaries.
144 var schema = { range: [1, 3] };
145 ajv.validate(schema, 1); // true
146 ajv.validate(schema, 2); // true
147 ajv.validate(schema, 3); // true
148 ajv.validate(schema, 0.99); // false
149 ajv.validate(schema, 3.01); // false
151 var schema = { range: [1, 3], exclusiveRange: true };
152 ajv.validate(schema, 1.01); // true
153 ajv.validate(schema, 2); // true
154 ajv.validate(schema, 2.99); // true
155 ajv.validate(schema, 1); // false
156 ajv.validate(schema, 3); // false
160 ### Keywords for strings
164 This keyword allows to use regular expressions with flags in schemas (the standard `pattern` keyword does not support flags).
166 This keyword applies only to strings. If the data is not a string, the validation succeeds.
168 The value of this keyword can be either a string (the result of `regexp.toString()`) or an object with the properties `pattern` and `flags` (the same strings that should be passed to RegExp constructor).
174 foo: { regexp: '/foo/i' },
175 bar: { regexp: { pattern: 'bar', flags: 'i' } }
191 #### `formatMaximum` / `formatMinimum` and `formatExclusiveMaximum` / `formatExclusiveMinimum`
193 These keywords allow to define minimum/maximum constraints when the format keyword defines ordering.
195 These keywords apply only to strings. If the data is not a string, the validation succeeds.
197 The value of keyword `formatMaximum` (`formatMinimum`) should be a string. This value is the maximum (minimum) allowed value for the data to be valid as determined by `format` keyword. If `format` is not present schema compilation will throw exception.
199 When this keyword is added, it defines comparison rules for formats `"date"`, `"time"` and `"date-time"`. Custom formats also can have comparison rules. See [addFormat](https://github.com/epoberezkin/ajv#api-addformat) method.
201 The value of keyword `formatExclusiveMaximum` (`formatExclusiveMinimum`) should be a boolean value. These keyword cannot be used without `formatMaximum` (`formatMinimum`). If this keyword value is equal to `true`, the data to be valid should not be equal to the value in `formatMaximum` (`formatMinimum`) keyword.
204 require('ajv-keywords')(ajv, ['formatMinimum', 'formatMaximum']);
208 formatMinimum: '2016-02-06',
209 formatMaximum: '2016-12-27',
210 formatExclusiveMaximum: true
213 var validDataList = ['2016-02-06', '2016-12-26', 1];
215 var invalidDataList = ['2016-02-05', '2016-12-27', 'abc'];
221 This keyword allows a string to be modified before validation.
223 These keywords apply only to strings. If the data is not a string, the transform is skipped.
225 There are limitation due to how ajv is written:
226 - a stand alone string cannot be transformed. ie `data = 'a'; ajv.validate(schema, data);`
227 - currently cannot work with `ajv-pack`
229 **Supported options:**
230 - `trim`: remove whitespace from start and end
231 - `trimLeft`: remove whitespace from start
232 - `trimRight`: remove whitespace from end
233 - `toLowerCase`: case string to all lower case
234 - `toUpperCase`: case string to all upper case
235 - `toEnumCase`: case string to match case in schema
237 Options are applied in the order they are listed.
239 Note: `toEnumCase` requires that all allowed values are unique when case insensitive.
241 **Example: multiple options**
243 require('ajv-keywords')(ajv, ['transform']);
249 transform:['trim','toLowerCase']
253 var data = [' MixCase '];
254 ajv.validate(schema, data);
255 console.log(data); // ['mixcase']
259 **Example: `enumcase`**
261 require('ajv-keywords')(ajv, ['transform']);
267 transform:['trim','toEnumCase'],
272 var data = ['ph',' Ph','PH','pH '];
273 ajv.validate(schema, data);
274 console.log(data); // ['pH','pH','pH','pH']
278 ### Keywords for arrays
280 #### `uniqueItemProperties`
282 The keyword allows to check that some properties in array items are unique.
284 This keyword applies only to arrays. If the data is not an array, the validation succeeds.
286 The value of this keyword must be an array of strings - property names that should have unique values across all items.
289 var schema = { uniqueItemProperties: [ "id", "name" ] };
299 { id: 1 }, // duplicate "id"
304 { id: 1, name: "taco" },
305 { id: 2, name: "taco" }, // duplicate "name"
306 { id: 3, name: "salsa" }
310 This keyword is contributed by [@blainesch](https://github.com/blainesch).
313 ### Keywords for objects
317 This keyword allows to require the presence of all properties used in `properties` keyword in the same schema object.
319 This keyword applies only to objects. If the data is not an object, the validation succeeds.
321 The value of this keyword must be boolean.
323 If the value of the keyword is `false`, the validation succeeds.
325 If the value of the keyword is `true`, the validation succeeds if the data contains all properties defined in `properties` keyword (in the same schema object).
327 If the `properties` keyword is not present in the same schema object, schema compilation will throw exception.
332 foo: {type: 'number'},
333 bar: {type: 'number'}
338 var validData = { foo: 1, bar: 2 };
339 var alsoValidData = { foo: 1, bar: 2, baz: 3 };
341 var invalidDataList = [ {}, { foo: 1 }, { bar: 2 } ];
347 This keyword allows to require the presence of any (at least one) property from the list.
349 This keyword applies only to objects. If the data is not an object, the validation succeeds.
351 The value of this keyword must be an array of strings, each string being a property name. For data object to be valid at least one of the properties in this array should be present in the object.
355 anyRequired: ['foo', 'bar']
358 var validData = { foo: 1 };
359 var alsoValidData = { foo: 1, bar: 2 };
361 var invalidDataList = [ {}, { baz: 3 } ];
367 This keyword allows to require the presence of only one property from the list.
369 This keyword applies only to objects. If the data is not an object, the validation succeeds.
371 The value of this keyword must be an array of strings, each string being a property name. For data object to be valid exactly one of the properties in this array should be present in the object.
375 oneRequired: ['foo', 'bar']
378 var validData = { foo: 1 };
379 var alsoValidData = { bar: 2, baz: 3 };
381 var invalidDataList = [ {}, { baz: 3 }, { foo: 1, bar: 2 } ];
385 #### `patternRequired`
387 This keyword allows to require the presence of properties that match some pattern(s).
389 This keyword applies only to objects. If the data is not an object, the validation succeeds.
391 The value of this keyword should be an array of strings, each string being a regular expression. For data object to be valid each regular expression in this array should match at least one property name in the data object.
393 If the array contains multiple regular expressions, more than one expression can match the same property name.
396 var schema = { patternRequired: [ 'f.*o', 'b.*r' ] };
398 var validData = { foo: 1, bar: 2 };
399 var alsoValidData = { foobar: 3 };
401 var invalidDataList = [ {}, { foo: 1 }, { bar: 2 } ];
407 This keyword allows to prohibit that any of the properties in the list is present in the object.
409 This keyword applies only to objects. If the data is not an object, the validation succeeds.
411 The value of this keyword should be an array of strings, each string being a property name. For data object to be valid none of the properties in this array should be present in the object.
414 var schema = { prohibited: ['foo', 'bar']};
416 var validData = { baz: 1 };
417 var alsoValidData = {};
419 var invalidDataList = [
426 __Please note__: `{prohibited: ['foo', 'bar']}` is equivalent to `{not: {anyRequired: ['foo', 'bar']}}` (i.e. it has the same validation result for any data).
429 #### `deepProperties`
431 This keyword allows to validate deep properties (identified by JSON pointers).
433 This keyword applies only to objects. If the data is not an object, the validation succeeds.
435 The value should be an object, where keys are JSON pointers to the data, starting from the current position in data, and the values are JSON schemas. For data object to be valid the value of each JSON pointer should be valid according to the corresponding schema.
441 "/users/1/role": { "enum": ["admin"] }
455 var alsoValidData = {
474 var alsoInvalidData = {
487 This keyword allows to check that some deep properties (identified by JSON pointers) are available.
489 This keyword applies only to objects. If the data is not an object, the validation succeeds.
491 The value should be an array of JSON pointers to the data, starting from the current position in data. For data object to be valid each JSON pointer should be some existing part of the data.
496 deepRequired: ["/users/1/role"]
519 See [json-schema-org/json-schema-spec#203](https://github.com/json-schema-org/json-schema-spec/issues/203#issue-197211916) for an example of the equivalent schema without `deepRequired` keyword.
522 ### Compound keywords
524 #### `switch` (deprecated)
526 __Please note__: this keyword is provided to preserve backward compatibility with previous versions of Ajv. It is strongly recommended to use `if`/`then`/`else` keywords instead, as they have been added to the draft-07 of JSON Schema specification.
528 This keyword allows to perform advanced conditional validation.
530 The value of the keyword is the array of if/then clauses. Each clause is the object with the following properties:
532 - `if` (optional) - the value is JSON-schema
533 - `then` (required) - the value is JSON-schema or boolean
534 - `continue` (optional) - the value is boolean
536 The validation process is dynamic; all clauses are executed sequentially in the following way:
539 1. `if` property is JSON-schema according to which the data is:
540 1. valid => go to step 2.
541 2. invalid => go to the NEXT clause, if this was the last clause the validation of `switch` SUCCEEDS.
542 2. `if` property is absent => go to step 2.
544 1. `then` property is `true` or it is JSON-schema according to which the data is valid => go to step 3.
545 2. `then` property is `false` or it is JSON-schema according to which the data is invalid => the validation of `switch` FAILS.
547 1. `continue` property is `true` => go to the NEXT clause, if this was the last clause the validation of `switch` SUCCEEDS.
548 2. `continue` property is `false` or absent => validation of `switch` SUCCEEDS.
551 require('ajv-keywords')(ajv, 'switch');
558 { if: { not: { minimum: 1 } }, then: false },
559 { if: { maximum: 10 }, then: true },
560 { if: { maximum: 100 }, then: { multipleOf: 10 } },
561 { if: { maximum: 1000 }, then: { multipleOf: 100 } },
567 var validItems = [1, 5, 10, 20, 50, 100, 200, 500, 1000];
569 var invalidItems = [1, 0, 2000, 11, 57, 123, 'foo'];
572 The above schema is equivalent to (for example):
579 if: { minimum: 1, maximum: 10 },
582 if: { maximum: 100 },
583 then: { multipleOf: 10 },
585 if: { maximum: 1000 },
586 then: { multipleOf: 100 },
595 #### `select`/`selectCases`/`selectDefault`
597 These keywords allow to choose the schema to validate the data based on the value of some property in the validated data.
599 These keywords must be present in the same schema object (`selectDefault` is optional).
601 The value of `select` keyword should be a [$data reference](https://github.com/epoberezkin/ajv/tree/5.0.2-beta.0#data-reference) that points to any primitive JSON type (string, number, boolean or null) in the data that is validated. You can also use a constant of primitive type as the value of this keyword (e.g., for debugging purposes).
603 The value of `selectCases` keyword must be an object where each property name is a possible string representation of the value of `select` keyword and each property value is a corresponding schema (from draft-06 it can be boolean) that must be used to validate the data.
605 The value of `selectDefault` keyword is a schema (from draft-06 it can be boolean) that must be used to validate the data in case `selectCases` has no key equal to the stringified value of `select` keyword.
607 The validation succeeds in one of the following cases:
608 - the validation of data using selected schema succeeds,
609 - none of the schemas is selected for validation,
610 - the value of select is undefined (no property in the data that the data reference points to).
612 If `select` value (in data) is not a primitive type the validation fails.
614 __Please note__: these keywords require Ajv `$data` option to support [$data reference](https://github.com/epoberezkin/ajv/tree/5.0.2-beta.0#data-reference).
618 require('ajv-keywords')(ajv, 'select');
624 kind: { type: 'string' }
626 select: { $data: '0/kind' },
632 foo: { type: 'string' }
634 additionalProperties: false
640 bar: { type: 'number' }
642 additionalProperties: false
647 not: { enum: ['foo', 'bar'] }
652 var validDataList = [
653 { kind: 'foo', foo: 'any' },
654 { kind: 'bar', bar: 1 },
655 { kind: 'anything_else', not_bar_or_foo: 'any value' }
658 var invalidDataList = [
659 { kind: 'foo' }, // no propery foo
660 { kind: 'bar' }, // no propery bar
661 { kind: 'foo', foo: 'any', another: 'any value' }, // additional property
662 { kind: 'bar', bar: 1, another: 'any value' }, // additional property
663 { kind: 'anything_else', foo: 'any' } // property foo not allowed
664 { kind: 'anything_else', bar: 1 } // property bar not allowed
668 __Please note__: the current implementation is BETA. It does not allow using relative URIs in $ref keywords in schemas in `selectCases` and `selectDefault` that point outside of these schemas. The workaround is to use absolute URIs (that can point to any (sub-)schema added to Ajv, including those inside the current root schema where `select` is used). See [tests](https://github.com/epoberezkin/ajv-keywords/blob/v2.0.0/spec/tests/select.json#L314).
671 ### Keywords for all types
673 #### `dynamicDefaults`
675 This keyword allows to assign dynamic defaults to properties, such as timestamps, unique IDs etc.
677 This keyword only works if `useDefaults` options is used and not inside `anyOf` keywords etc., in the same way as [default keyword treated by Ajv](https://github.com/epoberezkin/ajv#assigning-defaults).
679 The keyword should be added on the object level. Its value should be an object with each property corresponding to a property name, in the same way as in standard `properties` keyword. The value of each property can be:
681 - an identifier of default function (a string)
682 - an object with properties `func` (an identifier) and `args` (an object with parameters that will be passed to this function during schema compilation - see examples).
684 The properties used in `dynamicDefaults` should not be added to `required` keyword (or validation will fail), because unlike `default` this keyword is processed after validation.
686 There are several predefined dynamic default functions:
688 - `"timestamp"` - current timestamp in milliseconds
689 - `"datetime"` - current date and time as string (ISO, valid according to `date-time` format)
690 - `"date"` - current date as string (ISO, valid according to `date` format)
691 - `"time"` - current time as string (ISO, valid according to `time` format)
692 - `"random"` - pseudo-random number in [0, 1) interval
693 - `"randomint"` - pseudo-random integer number. If string is used as a property value, the function will randomly return 0 or 1. If object `{ func: 'randomint', args: { max: N } }` is used then the default will be an integer number in [0, N) interval.
694 - `"seq"` - sequential integer number starting from 0. If string is used as a property value, the default sequence will be used. If object `{ func: 'seq', args: { name: 'foo'} }` is used then the sequence with name `"foo"` will be used. Sequences are global, even if different ajv instances are used.
701 r: { func: 'randomint', args: { max: 100 } },
702 id: { func: 'seq', args: { name: 'id' } }
712 exclusiveMaximum: 100
722 ajv.validate(data); // true
723 data; // { ts: '2016-12-01T22:07:28.829Z', r: 25, id: 0 }
726 ajv.validate(data1); // true
727 data1; // { ts: '2016-12-01T22:07:29.832Z', r: 68, id: 1 }
729 ajv.validate(data1); // true
730 data1; // didn't change, as all properties were defined
733 When using the `useDefaults` option value `"empty"`, properties and items equal to `null` or `""` (empty string) will be considered missing and assigned defaults. Use the `allOf` [compound keyword](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#compound-keywords) to execute `dynamicDefaults` before validation.
741 r: { func: 'randomint', args: { min: 5, max: 100 } },
742 id: { func: 'seq', args: { name: 'id' } }
754 exclusiveMaximum: 100
765 var data = { ts: '', r: null };
766 ajv.validate(data); // true
767 data; // { ts: '2016-12-01T22:07:28.829Z', r: 25, id: 0 }
770 You can add your own dynamic default function to be recognised by this keyword:
773 var uuid = require('uuid');
775 function uuidV4() { return uuid.v4(); }
777 var definition = require('ajv-keywords').get('dynamicDefaults').definition;
778 // or require('ajv-keywords/keywords/dynamicDefaults').definition;
779 definition.DEFAULTS.uuid = uuidV4;
782 dynamicDefaults: { id: 'uuid' },
783 properties: { id: { type: 'string', format: 'uuid' } }
787 ajv.validate(schema, data); // true
788 data; // { id: 'a1183fbe-697b-4030-9bcc-cfeb282a9150' };
791 ajv.validate(schema, data1); // true
792 data1; // { id: '5b008de7-1669-467a-a5c6-70fa244d7209' }
795 You also can define dynamic default that accepts parameters, e.g. version of uuid:
798 var uuid = require('uuid');
800 function getUuid(args) {
801 var version = 'v' + (arvs && args.v || 4);
803 return uuid[version]();
807 var definition = require('ajv-keywords').get('dynamicDefaults').definition;
808 definition.DEFAULTS.uuid = getUuid;
813 id2: { func: 'uuid', v: 4 }, // v4
814 id3: { func: 'uuid', v: 1 } // v1
822 To report a security vulnerability, please use the
823 [Tidelift security contact](https://tidelift.com/security).
824 Tidelift will coordinate the fix and disclosure.
826 Please do NOT report security vulnerabilities via GitHub issues.
829 ## Open-source software support
831 Ajv-keywords is a part of [Tidelift subscription](https://tidelift.com/subscription/pkg/npm-ajv-keywords?utm_source=npm-ajv-keywords&utm_medium=referral&utm_campaign=readme) - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers.
836 [MIT](https://github.com/epoberezkin/ajv-keywords/blob/master/LICENSE)