You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

820 lines
25 KiB

4 years ago
  1. # ajv-keywords
  2. Custom JSON-Schema keywords for [Ajv](https://github.com/epoberezkin/ajv) validator
  3. [![Build Status](https://travis-ci.org/epoberezkin/ajv-keywords.svg?branch=master)](https://travis-ci.org/epoberezkin/ajv-keywords)
  4. [![npm](https://img.shields.io/npm/v/ajv-keywords.svg)](https://www.npmjs.com/package/ajv-keywords)
  5. [![npm downloads](https://img.shields.io/npm/dm/ajv-keywords.svg)](https://www.npmjs.com/package/ajv-keywords)
  6. [![Coverage Status](https://coveralls.io/repos/github/epoberezkin/ajv-keywords/badge.svg?branch=master)](https://coveralls.io/github/epoberezkin/ajv-keywords?branch=master)
  7. [![Greenkeeper badge](https://badges.greenkeeper.io/epoberezkin/ajv-keywords.svg)](https://greenkeeper.io/)
  8. [![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv)
  9. ## Contents
  10. - [Install](#install)
  11. - [Usage](#usage)
  12. - [Keywords](#keywords)
  13. - [Types](#types)
  14. - [typeof](#typeof)
  15. - [instanceof](#instanceof)
  16. - [Keywords for numbers](#keywords-for-numbers)
  17. - [range and exclusiveRange](#range-and-exclusiverange)
  18. - [Keywords for strings](#keywords-for-strings)
  19. - [regexp](#regexp)
  20. - [formatMaximum / formatMinimum and formatExclusiveMaximum / formatExclusiveMinimum](#formatmaximum--formatminimum-and-formatexclusivemaximum--formatexclusiveminimum)
  21. - [transform](#transform)<sup>\*</sup>
  22. - [Keywords for arrays](#keywords-for-arrays)
  23. - [uniqueItemProperties](#uniqueitemproperties)
  24. - [Keywords for objects](#keywords-for-objects)
  25. - [allRequired](#allrequired)
  26. - [anyRequired](#anyrequired)
  27. - [oneRequired](#onerequired)
  28. - [patternRequired](#patternrequired)
  29. - [prohibited](#prohibited)
  30. - [deepProperties](#deepproperties)
  31. - [deepRequired](#deeprequired)
  32. - [Compound keywords](#compound-keywords)
  33. - [switch](#switch) (deprecated)
  34. - [select/selectCases/selectDefault](#selectselectcasesselectdefault) (BETA)
  35. - [Keywords for all types](#keywords-for-all-types)
  36. - [dynamicDefaults](#dynamicdefaults)<sup>\*</sup>
  37. - [License](#license)
  38. <sup>\*</sup> - keywords that modify data
  39. ## Install
  40. ```
  41. npm install ajv-keywords
  42. ```
  43. ## Usage
  44. To add all available keywords:
  45. ```javascript
  46. var Ajv = require('ajv');
  47. var ajv = new Ajv;
  48. require('ajv-keywords')(ajv);
  49. ajv.validate({ instanceof: 'RegExp' }, /.*/); // true
  50. ajv.validate({ instanceof: 'RegExp' }, '.*'); // false
  51. ```
  52. To add a single keyword:
  53. ```javascript
  54. require('ajv-keywords')(ajv, 'instanceof');
  55. ```
  56. To add multiple keywords:
  57. ```javascript
  58. require('ajv-keywords')(ajv, ['typeof', 'instanceof']);
  59. ```
  60. To add a single keyword in browser (to avoid adding unused code):
  61. ```javascript
  62. require('ajv-keywords/keywords/instanceof')(ajv);
  63. ```
  64. ## Keywords
  65. ### Types
  66. #### `typeof`
  67. Based on JavaScript `typeof` operation.
  68. The value of the keyword should be a string (`"undefined"`, `"string"`, `"number"`, `"object"`, `"function"`, `"boolean"` or `"symbol"`) or array of strings.
  69. 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).
  70. ```
  71. ajv.validate({ typeof: 'undefined' }, undefined); // true
  72. ajv.validate({ typeof: 'undefined' }, null); // false
  73. ajv.validate({ typeof: ['undefined', 'object'] }, null); // true
  74. ```
  75. #### `instanceof`
  76. Based on JavaScript `instanceof` operation.
  77. The value of the keyword should be a string (`"Object"`, `"Array"`, `"Function"`, `"Number"`, `"String"`, `"Date"`, `"RegExp"`, `"Promise"` or `"Buffer"`) or array of strings.
  78. To pass validation the result of `data instanceof ...` operation on the value should be true:
  79. ```
  80. ajv.validate({ instanceof: 'Array' }, []); // true
  81. ajv.validate({ instanceof: 'Array' }, {}); // false
  82. ajv.validate({ instanceof: ['Array', 'Function'] }, function(){}); // true
  83. ```
  84. You can add your own constructor function to be recognised by this keyword:
  85. ```javascript
  86. function MyClass() {}
  87. var instanceofDefinition = require('ajv-keywords').get('instanceof').definition;
  88. // or require('ajv-keywords/keywords/instanceof').definition;
  89. instanceofDefinition.CONSTRUCTORS.MyClass = MyClass;
  90. ajv.validate({ instanceof: 'MyClass' }, new MyClass); // true
  91. ```
  92. ### Keywords for numbers
  93. #### `range` and `exclusiveRange`
  94. Syntax sugar for the combination of minimum and maximum keywords, also fails schema compilation if there are no numbers in the range.
  95. The value of this keyword must be the array consisting of two numbers, the second must be greater or equal than the first one.
  96. 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.
  97. ```javascript
  98. var schema = { range: [1, 3] };
  99. ajv.validate(schema, 1); // true
  100. ajv.validate(schema, 2); // true
  101. ajv.validate(schema, 3); // true
  102. ajv.validate(schema, 0.99); // false
  103. ajv.validate(schema, 3.01); // false
  104. var schema = { range: [1, 3], exclusiveRange: true };
  105. ajv.validate(schema, 1.01); // true
  106. ajv.validate(schema, 2); // true
  107. ajv.validate(schema, 2.99); // true
  108. ajv.validate(schema, 1); // false
  109. ajv.validate(schema, 3); // false
  110. ```
  111. ### Keywords for strings
  112. #### `regexp`
  113. This keyword allows to use regular expressions with flags in schemas (the standard `pattern` keyword does not support flags).
  114. This keyword applies only to strings. If the data is not a string, the validation succeeds.
  115. 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).
  116. ```javascript
  117. var schema = {
  118. type: 'object',
  119. properties: {
  120. foo: { regexp: '/foo/i' },
  121. bar: { regexp: { pattern: 'bar', flags: 'i' } }
  122. }
  123. };
  124. var validData = {
  125. foo: 'Food',
  126. bar: 'Barmen'
  127. };
  128. var invalidData = {
  129. foo: 'fog',
  130. bar: 'bad'
  131. };
  132. ```
  133. #### `formatMaximum` / `formatMinimum` and `formatExclusiveMaximum` / `formatExclusiveMinimum`
  134. These keywords allow to define minimum/maximum constraints when the format keyword defines ordering.
  135. These keywords apply only to strings. If the data is not a string, the validation succeeds.
  136. 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.
  137. 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.
  138. 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.
  139. ```javascript
  140. require('ajv-keywords')(ajv, ['formatMinimum', 'formatMaximum']);
  141. var schema = {
  142. format: 'date',
  143. formatMinimum: '2016-02-06',
  144. formatMaximum: '2016-12-27',
  145. formatExclusiveMaximum: true
  146. }
  147. var validDataList = ['2016-02-06', '2016-12-26', 1];
  148. var invalidDataList = ['2016-02-05', '2016-12-27', 'abc'];
  149. ```
  150. #### `transform`
  151. This keyword allows a string to be modified before validation.
  152. These keywords apply only to strings. If the data is not a string, the transform is skipped.
  153. There are limitation due to how ajv is written:
  154. - a stand alone string cannot be transformed. ie `data = 'a'; ajv.validate(schema, data);`
  155. - currently cannot work with `ajv-pack`
  156. **Supported options:**
  157. - `trim`: remove whitespace from start and end
  158. - `trimLeft`: remove whitespace from start
  159. - `trimRight`: remove whitespace from end
  160. - `toLowerCase`: case string to all lower case
  161. - `toUpperCase`: case string to all upper case
  162. - `toEnumCase`: case string to match case in schema
  163. Options are applied in the order they are listed.
  164. Note: `toEnumCase` requires that all allowed values are unique when case insensitive.
  165. **Example: multiple options**
  166. ```javascript
  167. require('ajv-keywords')(ajv, ['transform']);
  168. var schema = {
  169. type: 'array',
  170. items: {
  171. type:'string',
  172. transform:['trim','toLowerCase']
  173. }
  174. };
  175. var data = [' MixCase '];
  176. ajv.validate(schema, data);
  177. console.log(data); // ['mixcase']
  178. ```
  179. **Example: `enumcase`**
  180. ```javascript
  181. require('ajv-keywords')(ajv, ['transform']);
  182. var schema = {
  183. type: 'array',
  184. items: {
  185. type:'string',
  186. transform:['trim','toEnumCase'],
  187. enum:['pH']
  188. }
  189. };
  190. var data = ['ph',' Ph','PH','pH '];
  191. ajv.validate(schema, data);
  192. console.log(data); // ['pH','pH','pH','pH']
  193. ```
  194. ### Keywords for arrays
  195. #### `uniqueItemProperties`
  196. The keyword allows to check that some properties in array items are unique.
  197. This keyword applies only to arrays. If the data is not an array, the validation succeeds.
  198. The value of this keyword must be an array of strings - property names that should have unique values across all items.
  199. ```javascript
  200. var schema = { uniqueItemProperties: [ "id", "name" ] };
  201. var validData = [
  202. { id: 1 },
  203. { id: 2 },
  204. { id: 3 }
  205. ];
  206. var invalidData1 = [
  207. { id: 1 },
  208. { id: 1 }, // duplicate "id"
  209. { id: 3 }
  210. ];
  211. var invalidData2 = [
  212. { id: 1, name: "taco" },
  213. { id: 2, name: "taco" }, // duplicate "name"
  214. { id: 3, name: "salsa" }
  215. ];
  216. ```
  217. This keyword is contributed by [@blainesch](https://github.com/blainesch).
  218. ### Keywords for objects
  219. #### `allRequired`
  220. This keyword allows to require the presence of all properties used in `properties` keyword in the same schema object.
  221. This keyword applies only to objects. If the data is not an object, the validation succeeds.
  222. The value of this keyword must be boolean.
  223. If the value of the keyword is `false`, the validation succeeds.
  224. 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).
  225. If the `properties` keyword is not present in the same schema object, schema compilation will throw exception.
  226. ```javascript
  227. var schema = {
  228. properties: {
  229. foo: {type: 'number'},
  230. bar: {type: 'number'}
  231. }
  232. allRequired: true
  233. };
  234. var validData = { foo: 1, bar: 2 };
  235. var alsoValidData = { foo: 1, bar: 2, baz: 3 };
  236. var invalidDataList = [ {}, { foo: 1 }, { bar: 2 } ];
  237. ```
  238. #### `anyRequired`
  239. This keyword allows to require the presence of any (at least one) property from the list.
  240. This keyword applies only to objects. If the data is not an object, the validation succeeds.
  241. 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.
  242. ```javascript
  243. var schema = {
  244. anyRequired: ['foo', 'bar']
  245. };
  246. var validData = { foo: 1 };
  247. var alsoValidData = { foo: 1, bar: 2 };
  248. var invalidDataList = [ {}, { baz: 3 } ];
  249. ```
  250. #### `oneRequired`
  251. This keyword allows to require the presence of only one property from the list.
  252. This keyword applies only to objects. If the data is not an object, the validation succeeds.
  253. 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.
  254. ```javascript
  255. var schema = {
  256. oneRequired: ['foo', 'bar']
  257. };
  258. var validData = { foo: 1 };
  259. var alsoValidData = { bar: 2, baz: 3 };
  260. var invalidDataList = [ {}, { baz: 3 }, { foo: 1, bar: 2 } ];
  261. ```
  262. #### `patternRequired`
  263. This keyword allows to require the presence of properties that match some pattern(s).
  264. This keyword applies only to objects. If the data is not an object, the validation succeeds.
  265. 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.
  266. If the array contains multiple regular expressions, more than one expression can match the same property name.
  267. ```javascript
  268. var schema = { patternRequired: [ 'f.*o', 'b.*r' ] };
  269. var validData = { foo: 1, bar: 2 };
  270. var alsoValidData = { foobar: 3 };
  271. var invalidDataList = [ {}, { foo: 1 }, { bar: 2 } ];
  272. ```
  273. #### `prohibited`
  274. This keyword allows to prohibit that any of the properties in the list is present in the object.
  275. This keyword applies only to objects. If the data is not an object, the validation succeeds.
  276. 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.
  277. ```
  278. var schema = { prohibited: ['foo', 'bar']};
  279. var validData = { baz: 1 };
  280. var alsoValidData = {};
  281. var invalidDataList = [
  282. { foo: 1 },
  283. { bar: 2 },
  284. { foo: 1, bar: 2}
  285. ];
  286. ```
  287. __Please note__: `{prohibited: ['foo', 'bar']}` is equivalent to `{not: {anyRequired: ['foo', 'bar']}}` (i.e. it has the same validation result for any data).
  288. #### `deepProperties`
  289. This keyword allows to validate deep properties (identified by JSON pointers).
  290. This keyword applies only to objects. If the data is not an object, the validation succeeds.
  291. 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.
  292. ```javascript
  293. var schema = {
  294. type: 'object',
  295. deepProperties: {
  296. "/users/1/role": { "enum": ["admin"] }
  297. }
  298. };
  299. var validData = {
  300. users: [
  301. {},
  302. {
  303. id: 123,
  304. role: 'admin'
  305. }
  306. ]
  307. };
  308. var alsoValidData = {
  309. users: {
  310. "1": {
  311. id: 123,
  312. role: 'admin'
  313. }
  314. }
  315. };
  316. var invalidData = {
  317. users: [
  318. {},
  319. {
  320. id: 123,
  321. role: 'user'
  322. }
  323. ]
  324. };
  325. var alsoInvalidData = {
  326. users: {
  327. "1": {
  328. id: 123,
  329. role: 'user'
  330. }
  331. }
  332. };
  333. ```
  334. #### `deepRequired`
  335. This keyword allows to check that some deep properties (identified by JSON pointers) are available.
  336. This keyword applies only to objects. If the data is not an object, the validation succeeds.
  337. 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.
  338. ```javascript
  339. var schema = {
  340. type: 'object',
  341. deepRequired: ["/users/1/role"]
  342. };
  343. var validData = {
  344. users: [
  345. {},
  346. {
  347. id: 123,
  348. role: 'admin'
  349. }
  350. ]
  351. };
  352. var invalidData = {
  353. users: [
  354. {},
  355. {
  356. id: 123
  357. }
  358. ]
  359. };
  360. ```
  361. 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.
  362. ### Compound keywords
  363. #### `switch` (deprecated)
  364. __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.
  365. This keyword allows to perform advanced conditional validation.
  366. The value of the keyword is the array of if/then clauses. Each clause is the object with the following properties:
  367. - `if` (optional) - the value is JSON-schema
  368. - `then` (required) - the value is JSON-schema or boolean
  369. - `continue` (optional) - the value is boolean
  370. The validation process is dynamic; all clauses are executed sequentially in the following way:
  371. 1. `if`:
  372. 1. `if` property is JSON-schema according to which the data is:
  373. 1. valid => go to step 2.
  374. 2. invalid => go to the NEXT clause, if this was the last clause the validation of `switch` SUCCEEDS.
  375. 2. `if` property is absent => go to step 2.
  376. 2. `then`:
  377. 1. `then` property is `true` or it is JSON-schema according to which the data is valid => go to step 3.
  378. 2. `then` property is `false` or it is JSON-schema according to which the data is invalid => the validation of `switch` FAILS.
  379. 3. `continue`:
  380. 1. `continue` property is `true` => go to the NEXT clause, if this was the last clause the validation of `switch` SUCCEEDS.
  381. 2. `continue` property is `false` or absent => validation of `switch` SUCCEEDS.
  382. ```javascript
  383. require('ajv-keywords')(ajv, 'switch');
  384. var schema = {
  385. type: 'array',
  386. items: {
  387. type: 'integer',
  388. 'switch': [
  389. { if: { not: { minimum: 1 } }, then: false },
  390. { if: { maximum: 10 }, then: true },
  391. { if: { maximum: 100 }, then: { multipleOf: 10 } },
  392. { if: { maximum: 1000 }, then: { multipleOf: 100 } },
  393. { then: false }
  394. ]
  395. }
  396. };
  397. var validItems = [1, 5, 10, 20, 50, 100, 200, 500, 1000];
  398. var invalidItems = [1, 0, 2000, 11, 57, 123, 'foo'];
  399. ```
  400. The above schema is equivalent to (for example):
  401. ```javascript
  402. {
  403. type: 'array',
  404. items: {
  405. type: 'integer',
  406. if: { minimum: 1, maximum: 10 },
  407. then: true,
  408. else: {
  409. if: { maximum: 100 },
  410. then: { multipleOf: 10 },
  411. else: {
  412. if: { maximum: 1000 },
  413. then: { multipleOf: 100 },
  414. else: false
  415. }
  416. }
  417. }
  418. }
  419. ```
  420. #### `select`/`selectCases`/`selectDefault`
  421. These keywords allow to choose the schema to validate the data based on the value of some property in the validated data.
  422. These keywords must be present in the same schema object (`selectDefault` is optional).
  423. 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).
  424. 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.
  425. 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.
  426. The validation succeeds in one of the following cases:
  427. - the validation of data using selected schema succeeds,
  428. - none of the schemas is selected for validation,
  429. - the value of select is undefined (no property in the data that the data reference points to).
  430. If `select` value (in data) is not a primitive type the validation fails.
  431. __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).
  432. ```javascript
  433. require('ajv-keywords')(ajv, 'select');
  434. var schema = {
  435. type: object,
  436. required: ['kind'],
  437. properties: {
  438. kind: { type: 'string' }
  439. },
  440. select: { $data: '0/kind' },
  441. selectCases: {
  442. foo: {
  443. required: ['foo'],
  444. properties: {
  445. kind: {},
  446. foo: { type: 'string' }
  447. },
  448. additionalProperties: false
  449. },
  450. bar: {
  451. required: ['bar'],
  452. properties: {
  453. kind: {},
  454. bar: { type: 'number' }
  455. },
  456. additionalProperties: false
  457. }
  458. },
  459. selectDefault: {
  460. propertyNames: {
  461. not: { enum: ['foo', 'bar'] }
  462. }
  463. }
  464. };
  465. var validDataList = [
  466. { kind: 'foo', foo: 'any' },
  467. { kind: 'bar', bar: 1 },
  468. { kind: 'anything_else', not_bar_or_foo: 'any value' }
  469. ];
  470. var invalidDataList = [
  471. { kind: 'foo' }, // no propery foo
  472. { kind: 'bar' }, // no propery bar
  473. { kind: 'foo', foo: 'any', another: 'any value' }, // additional property
  474. { kind: 'bar', bar: 1, another: 'any value' }, // additional property
  475. { kind: 'anything_else', foo: 'any' } // property foo not allowed
  476. { kind: 'anything_else', bar: 1 } // property bar not allowed
  477. ];
  478. ```
  479. __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).
  480. ### Keywords for all types
  481. #### `dynamicDefaults`
  482. This keyword allows to assign dynamic defaults to properties, such as timestamps, unique IDs etc.
  483. 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).
  484. 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:
  485. - an identifier of default function (a string)
  486. - 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).
  487. 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.
  488. There are several predefined dynamic default functions:
  489. - `"timestamp"` - current timestamp in milliseconds
  490. - `"datetime"` - current date and time as string (ISO, valid according to `date-time` format)
  491. - `"date"` - current date as string (ISO, valid according to `date` format)
  492. - `"time"` - current time as string (ISO, valid according to `time` format)
  493. - `"random"` - pseudo-random number in [0, 1) interval
  494. - `"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.
  495. - `"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.
  496. ```javascript
  497. var schema = {
  498. type: 'object',
  499. dynamicDefaults: {
  500. ts: 'datetime',
  501. r: { func: 'randomint', args: { max: 100 } },
  502. id: { func: 'seq', args: { name: 'id' } }
  503. },
  504. properties: {
  505. ts: {
  506. type: 'string',
  507. format: 'date-time'
  508. },
  509. r: {
  510. type: 'integer',
  511. minimum: 0,
  512. exclusiveMaximum: 100
  513. },
  514. id: {
  515. type: 'integer',
  516. minimum: 0
  517. }
  518. }
  519. };
  520. var data = {};
  521. ajv.validate(data); // true
  522. data; // { ts: '2016-12-01T22:07:28.829Z', r: 25, id: 0 }
  523. var data1 = {};
  524. ajv.validate(data1); // true
  525. data1; // { ts: '2016-12-01T22:07:29.832Z', r: 68, id: 1 }
  526. ajv.validate(data1); // true
  527. data1; // didn't change, as all properties were defined
  528. ```
  529. 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.
  530. ```javascript
  531. var schema = {
  532. allOf: [
  533. {
  534. dynamicDefaults: {
  535. ts: 'datetime',
  536. r: { func: 'randomint', args: { min: 5, max: 100 } },
  537. id: { func: 'seq', args: { name: 'id' } }
  538. }
  539. },
  540. {
  541. type: 'object',
  542. properties: {
  543. ts: {
  544. type: 'string'
  545. },
  546. r: {
  547. type: 'number',
  548. minimum: 5,
  549. exclusiveMaximum: 100
  550. },
  551. id: {
  552. type: 'integer',
  553. minimum: 0
  554. }
  555. }
  556. }
  557. ]
  558. };
  559. var data = { ts: '', r: null };
  560. ajv.validate(data); // true
  561. data; // { ts: '2016-12-01T22:07:28.829Z', r: 25, id: 0 }
  562. ```
  563. You can add your own dynamic default function to be recognised by this keyword:
  564. ```javascript
  565. var uuid = require('uuid');
  566. function uuidV4() { return uuid.v4(); }
  567. var definition = require('ajv-keywords').get('dynamicDefaults').definition;
  568. // or require('ajv-keywords/keywords/dynamicDefaults').definition;
  569. definition.DEFAULTS.uuid = uuidV4;
  570. var schema = {
  571. dynamicDefaults: { id: 'uuid' },
  572. properties: { id: { type: 'string', format: 'uuid' } }
  573. };
  574. var data = {};
  575. ajv.validate(schema, data); // true
  576. data; // { id: 'a1183fbe-697b-4030-9bcc-cfeb282a9150' };
  577. var data1 = {};
  578. ajv.validate(schema, data1); // true
  579. data1; // { id: '5b008de7-1669-467a-a5c6-70fa244d7209' }
  580. ```
  581. You also can define dynamic default that accepts parameters, e.g. version of uuid:
  582. ```javascript
  583. var uuid = require('uuid');
  584. function getUuid(args) {
  585. var version = 'v' + (arvs && args.v || 4);
  586. return function() {
  587. return uuid[version]();
  588. };
  589. }
  590. var definition = require('ajv-keywords').get('dynamicDefaults').definition;
  591. definition.DEFAULTS.uuid = getUuid;
  592. var schema = {
  593. dynamicDefaults: {
  594. id1: 'uuid', // v4
  595. id2: { func: 'uuid', v: 4 }, // v4
  596. id3: { func: 'uuid', v: 1 } // v1
  597. }
  598. };
  599. ```
  600. ## License
  601. [MIT](https://github.com/epoberezkin/ajv-keywords/blob/master/LICENSE)