[484] | 1 | # Tiny Validator (for v4 JSON Schema) |
---|
| 2 | |
---|
| 3 | [](http://travis-ci.org/geraintluff/tv4) [](https://gemnasium.com/geraintluff/tv4) [](http://badge.fury.io/js/tv4) |
---|
| 4 | |
---|
| 5 | Use [json-schema](http://json-schema.org/) [draft v4](http://json-schema.org/latest/json-schema-core.html) to validate simple values and complex objects using a rich [validation vocabulary](http://json-schema.org/latest/json-schema-validation.html) ([examples](http://json-schema.org/examples.html)). |
---|
| 6 | |
---|
| 7 | There is support for `$ref` with JSON Pointer fragment paths (```other-schema.json#/properties/myKey```). |
---|
| 8 | |
---|
| 9 | ## Usage 1: Simple validation |
---|
| 10 | |
---|
| 11 | ```javascript |
---|
| 12 | var valid = tv4.validate(data, schema); |
---|
| 13 | ``` |
---|
| 14 | |
---|
| 15 | If validation returns ```false```, then an explanation of why validation failed can be found in ```tv4.error```. |
---|
| 16 | |
---|
| 17 | The error object will look something like: |
---|
| 18 | ```json |
---|
| 19 | { |
---|
| 20 | "code": 0, |
---|
| 21 | "message": "Invalid type: string", |
---|
| 22 | "dataPath": "/intKey", |
---|
| 23 | "schemaKey": "/properties/intKey/type" |
---|
| 24 | } |
---|
| 25 | ``` |
---|
| 26 | |
---|
| 27 | The `"code"` property will refer to one of the values in `tv4.errorCodes` - in this case, `tv4.errorCodes.INVALID_TYPE`. |
---|
| 28 | |
---|
| 29 | To enable external schema to be referenced, you use: |
---|
| 30 | ```javascript |
---|
| 31 | tv4.addSchema(url, schema); |
---|
| 32 | ``` |
---|
| 33 | |
---|
| 34 | If schemas are referenced (```$ref```) but not known, then validation will return ```true``` and the missing schema(s) will be listed in ```tv4.missing```. For more info see the API documentation below. |
---|
| 35 | |
---|
| 36 | ## Usage 2: Multi-threaded validation |
---|
| 37 | |
---|
| 38 | Storing the error and missing schemas does not work well in multi-threaded environments, so there is an alternative syntax: |
---|
| 39 | |
---|
| 40 | ```javascript |
---|
| 41 | var result = tv4.validateResult(data, schema); |
---|
| 42 | ``` |
---|
| 43 | |
---|
| 44 | The result will look something like: |
---|
| 45 | ```json |
---|
| 46 | { |
---|
| 47 | "valid": false, |
---|
| 48 | "error": {...}, |
---|
| 49 | "missing": [...] |
---|
| 50 | } |
---|
| 51 | ``` |
---|
| 52 | |
---|
| 53 | ## Usage 3: Multiple errors |
---|
| 54 | |
---|
| 55 | Normally, `tv4` stops when it encounters the first validation error. However, you can collect an array of validation errors using: |
---|
| 56 | |
---|
| 57 | ```javascript |
---|
| 58 | var result = tv4.validateMultiple(data, schema); |
---|
| 59 | ``` |
---|
| 60 | |
---|
| 61 | The result will look something like: |
---|
| 62 | ```json |
---|
| 63 | { |
---|
| 64 | "valid": false, |
---|
| 65 | "errors": [ |
---|
| 66 | {...}, |
---|
| 67 | ... |
---|
| 68 | ], |
---|
| 69 | "missing": [...] |
---|
| 70 | } |
---|
| 71 | ``` |
---|
| 72 | |
---|
| 73 | ## Asynchronous validation |
---|
| 74 | |
---|
| 75 | Support for asynchronous validation (where missing schemas are fetched) can be added by including an extra JavaScript file. Currently, the only version requires jQuery (`tv4.async-jquery.js`), but the code is very short and should be fairly easy to modify for other libraries (such as MooTools). |
---|
| 76 | |
---|
| 77 | Usage: |
---|
| 78 | |
---|
| 79 | ```javascript |
---|
| 80 | tv4.validate(data, schema, function (isValid, validationError) { ... }); |
---|
| 81 | ``` |
---|
| 82 | |
---|
| 83 | `validationFailure` is simply taken from `tv4.error`. |
---|
| 84 | |
---|
| 85 | ## Cyclical JavaScript objects |
---|
| 86 | |
---|
[487] | 87 | While they don't occur in proper JSON, JavaScript does support self-referencing objects. Any of the above calls support an optional third argument: `checkRecursive`. If true, tv4 will handle self-referencing objects properly - this slows down validation slightly, but that's better than a hanging script. |
---|
[484] | 88 | |
---|
| 89 | Consider this data, notice how both `a` and `b` refer to each other: |
---|
| 90 | |
---|
| 91 | ```javascript |
---|
| 92 | var a = {}; |
---|
| 93 | var b = { a: a }; |
---|
| 94 | a.b = b; |
---|
| 95 | var aSchema = { properties: { b: { $ref: 'bSchema' }}}; |
---|
| 96 | var bSchema = { properties: { a: { $ref: 'aSchema' }}}; |
---|
| 97 | tv4.addSchema('aSchema', aSchema); |
---|
| 98 | tv4.addSchema('bSchema', bSchema); |
---|
| 99 | ``` |
---|
| 100 | |
---|
[487] | 101 | If the `checkRecursive` argument were missing, this would throw a "too much recursion" error. |
---|
[484] | 102 | |
---|
[487] | 103 | To enable support for this, pass `true` as additional argument to any of the regular validation methods: |
---|
[484] | 104 | |
---|
| 105 | ```javascript |
---|
| 106 | tv4.validate(a, aSchema, true); |
---|
| 107 | tv4.validateResult(data, aSchema, true); |
---|
| 108 | tv4.validateMultiple(data, aSchema, true); |
---|
| 109 | ``` |
---|
| 110 | |
---|
[487] | 111 | ## The `banUnknownProperties` flag |
---|
| 112 | |
---|
| 113 | Sometimes, it is desirable to flag all unknown properties as an error. This is especially useful during development, to catch typos and the like, even when extra custom-defined properties are allowed. |
---|
| 114 | |
---|
| 115 | As such, tv4 implements ["ban unknown properties" mode](https://github.com/json-schema/json-schema/wiki/ban-unknown-properties-mode-\(v5-proposal\)), enabled by a fourth-argument flag: |
---|
| 116 | |
---|
| 117 | ```javascript |
---|
| 118 | tv4.validate(data, schema, checkRecursive, true); |
---|
| 119 | tv4.validateResult(data, schema, checkRecursive, true); |
---|
| 120 | tv4.validateMultiple(data, schema, checkRecursive, true); |
---|
| 121 | ``` |
---|
| 122 | |
---|
[484] | 123 | ## API |
---|
| 124 | |
---|
| 125 | There are additional api commands available for more complex use-cases: |
---|
| 126 | |
---|
| 127 | ##### addSchema(uri, schema) |
---|
| 128 | Pre-register a schema for reference by other schema and synchronous validation. |
---|
| 129 | |
---|
| 130 | ````js |
---|
| 131 | tv4.addSchema('http://example.com/schema', { ... }); |
---|
| 132 | ```` |
---|
| 133 | |
---|
| 134 | * `uri` the uri to identify this schema. |
---|
| 135 | * `schema` the schema object. |
---|
| 136 | |
---|
| 137 | Schemas that have their `id` property set can be added directly. |
---|
| 138 | |
---|
| 139 | ````js |
---|
| 140 | tv4.addSchema({ ... }); |
---|
| 141 | ```` |
---|
| 142 | |
---|
| 143 | ##### getSchema(uri) |
---|
| 144 | |
---|
| 145 | Return a schema from the cache. |
---|
| 146 | |
---|
| 147 | * `uri` the uri of the schema (may contain a `#` fragment) |
---|
| 148 | |
---|
| 149 | ````js |
---|
| 150 | var schema = tv4.getSchema('http://example.com/schema'); |
---|
| 151 | ```` |
---|
| 152 | |
---|
| 153 | ##### getSchemaMap() |
---|
| 154 | |
---|
| 155 | Return a shallow copy of the schema cache, mapping schema document URIs to schema objects. |
---|
| 156 | |
---|
| 157 | ```` |
---|
| 158 | var map = tv4.getSchemaMap(); |
---|
| 159 | |
---|
| 160 | var schema = map[uri]; |
---|
| 161 | ```` |
---|
| 162 | |
---|
| 163 | ##### getSchemaUris(filter) |
---|
| 164 | |
---|
| 165 | Return an Array with known schema document URIs. |
---|
| 166 | |
---|
| 167 | * `filter` optional RegExp to filter URIs |
---|
| 168 | |
---|
| 169 | ```` |
---|
| 170 | var arr = tv4.getSchemaUris(); |
---|
| 171 | |
---|
| 172 | // optional filter using a RegExp |
---|
| 173 | var arr = tv4.getSchemaUris(/^https?://example.com/); |
---|
| 174 | ```` |
---|
| 175 | |
---|
| 176 | ##### getMissingUris(filter) |
---|
| 177 | |
---|
| 178 | Return an Array with schema document URIs that are used as `$ref` in known schemas but which currently have no associated schema data. |
---|
| 179 | |
---|
| 180 | Use this in combination with `tv4.addSchema(uri, schema)` to preload the cache for complete synchronous validation with. |
---|
| 181 | |
---|
| 182 | * `filter` optional RegExp to filter URIs |
---|
| 183 | |
---|
| 184 | ```` |
---|
| 185 | var arr = tv4.getMissingUris(); |
---|
| 186 | |
---|
| 187 | // optional filter using a RegExp |
---|
| 188 | var arr = tv4.getMissingUris(/^https?://example.com/); |
---|
| 189 | ```` |
---|
| 190 | |
---|
| 191 | ##### dropSchemas() |
---|
| 192 | |
---|
| 193 | Drop all known schema document URIs from the cache. |
---|
| 194 | |
---|
| 195 | ```` |
---|
| 196 | tv4.dropSchemas(); |
---|
| 197 | ```` |
---|
| 198 | |
---|
| 199 | ##### freshApi() |
---|
| 200 | |
---|
| 201 | Return a new tv4 instance with no shared state. |
---|
| 202 | |
---|
| 203 | ```` |
---|
| 204 | var otherTV4 = tv4.freshApi(); |
---|
| 205 | ```` |
---|
| 206 | |
---|
| 207 | ##### reset() |
---|
| 208 | |
---|
| 209 | Manually reset validation status from the simple `tv4.validate(data, schema)`. Although tv4 will self reset on each validation there are some implementation scenarios where this is useful. |
---|
| 210 | |
---|
| 211 | ```` |
---|
| 212 | tv4.reset(); |
---|
| 213 | ```` |
---|
| 214 | |
---|
| 215 | ##### language(code) |
---|
| 216 | |
---|
| 217 | Select the language map used for reporting. |
---|
| 218 | |
---|
| 219 | * `code` is a language code, like `'en'` or `'en-gb'` |
---|
| 220 | |
---|
| 221 | ```` |
---|
| 222 | tv4.language('en-gb'); |
---|
| 223 | ```` |
---|
| 224 | |
---|
| 225 | ##### addLanguage(code, map) |
---|
| 226 | |
---|
| 227 | Add a new language map for selection by `tv4.language(code)` |
---|
| 228 | |
---|
| 229 | * `code` is new language code |
---|
| 230 | * `map` is an object mapping error IDs or constant names (e.g. `103` or `"NUMBER_MAXIMUM"`) to language strings. |
---|
| 231 | |
---|
| 232 | ```` |
---|
| 233 | tv4.addLanguage('fr', { ... }); |
---|
| 234 | |
---|
| 235 | // select for use |
---|
| 236 | tv4.language('fr') |
---|
| 237 | ```` |
---|
| 238 | |
---|
| 239 | ##### addFormat(format, validationFunction) |
---|
| 240 | |
---|
[487] | 241 | Add a custom format validator. (There are no built-in format validators.) |
---|
[484] | 242 | |
---|
| 243 | * `format` is a string, corresponding to the `"format"` value in schemas. |
---|
| 244 | * `validationFunction` is a function that either returns: |
---|
| 245 | * `null` (meaning no error) |
---|
| 246 | * an error string (explaining the reason for failure) |
---|
| 247 | |
---|
| 248 | ```` |
---|
| 249 | tv4.addFormat('decimal-digits', function (data, schema) { |
---|
| 250 | if (typeof data === 'string' && !/^[0-9]+$/.test(data)) { |
---|
| 251 | return null; |
---|
| 252 | } |
---|
| 253 | return "must be string of decimal digits"; |
---|
| 254 | }); |
---|
| 255 | ```` |
---|
| 256 | |
---|
| 257 | Alternatively, multiple formats can be added at the same time using an object: |
---|
| 258 | ```` |
---|
| 259 | tv4.addFormat({ |
---|
| 260 | 'my-format': function () {...}, |
---|
| 261 | 'other-format': function () {...} |
---|
| 262 | }); |
---|
| 263 | ```` |
---|
| 264 | |
---|
| 265 | ## Demos |
---|
| 266 | |
---|
| 267 | ### Basic usage |
---|
| 268 | <div class="content inline-demo" markdown="1" data-demo="demo1"> |
---|
| 269 | <pre class="code" id="demo1"> |
---|
| 270 | var schema = { |
---|
| 271 | "items": { |
---|
| 272 | "type": "boolean" |
---|
| 273 | } |
---|
| 274 | }; |
---|
| 275 | var data1 = [true, false]; |
---|
| 276 | var data2 = [true, 123]; |
---|
| 277 | |
---|
| 278 | alert("data 1: " + tv4.validate(data1, schema)); // true |
---|
| 279 | alert("data 2: " + tv4.validate(data2, schema)); // false |
---|
| 280 | alert("data 2 error: " + JSON.stringify(tv4.error, null, 4)); |
---|
| 281 | </pre> |
---|
| 282 | </div> |
---|
| 283 | |
---|
| 284 | ### Use of <code>$ref</code> |
---|
| 285 | <div class="content inline-demo" markdown="1" data-demo="demo2"> |
---|
| 286 | <pre class="code" id="demo2"> |
---|
| 287 | var schema = { |
---|
| 288 | "type": "array", |
---|
| 289 | "items": {"$ref": "#"} |
---|
| 290 | }; |
---|
| 291 | var data1 = [[], [[]]]; |
---|
| 292 | var data2 = [[], [true, []]]; |
---|
| 293 | |
---|
| 294 | alert("data 1: " + tv4.validate(data1, schema)); // true |
---|
| 295 | alert("data 2: " + tv4.validate(data2, schema)); // false |
---|
| 296 | </pre> |
---|
| 297 | </div> |
---|
| 298 | |
---|
| 299 | ### Missing schema |
---|
| 300 | <div class="content inline-demo" markdown="1" data-demo="demo3"> |
---|
| 301 | <pre class="code" id="demo3"> |
---|
| 302 | var schema = { |
---|
| 303 | "type": "array", |
---|
| 304 | "items": {"$ref": "http://example.com/schema" } |
---|
| 305 | }; |
---|
| 306 | var data = [1, 2, 3]; |
---|
| 307 | |
---|
| 308 | alert("Valid: " + tv4.validate(data, schema)); // true |
---|
| 309 | alert("Missing schemas: " + JSON.stringify(tv4.missing)); |
---|
| 310 | </pre> |
---|
| 311 | </div> |
---|
| 312 | |
---|
| 313 | ### Referencing remote schema |
---|
| 314 | <div class="content inline-demo" markdown="1" data-demo="demo4"> |
---|
| 315 | <pre class="code" id="demo4"> |
---|
| 316 | tv4.addSchema("http://example.com/schema", { |
---|
| 317 | "definitions": { |
---|
| 318 | "arrayItem": {"type": "boolean"} |
---|
| 319 | } |
---|
| 320 | }); |
---|
| 321 | var schema = { |
---|
| 322 | "type": "array", |
---|
| 323 | "items": {"$ref": "http://example.com/schema#/definitions/arrayItem" } |
---|
| 324 | }; |
---|
| 325 | var data1 = [true, false, true]; |
---|
| 326 | var data2 = [1, 2, 3]; |
---|
| 327 | |
---|
| 328 | alert("data 1: " + tv4.validate(data1, schema)); // true |
---|
| 329 | alert("data 2: " + tv4.validate(data2, schema)); // false |
---|
| 330 | </pre> |
---|
| 331 | </div> |
---|
| 332 | |
---|
| 333 | ## Supported platforms |
---|
| 334 | |
---|
| 335 | * Node.js |
---|
| 336 | * All modern browsers |
---|
| 337 | * IE >= 7 |
---|
| 338 | |
---|
| 339 | ## Installation |
---|
| 340 | |
---|
| 341 | You can manually download [`tv4.js`](https://raw.github.com/geraintluff/tv4/master/tv4.js) or the minified [`tv4.min.js`](https://raw.github.com/geraintluff/tv4/master/tv4.min.js) and include it in your html to create the global `tv4` variable. |
---|
| 342 | |
---|
| 343 | Alternately use it as a CommonJS module: |
---|
| 344 | |
---|
| 345 | ````js |
---|
| 346 | var tv4 = require('tv4'); |
---|
| 347 | ```` |
---|
| 348 | |
---|
| 349 | #### npm |
---|
| 350 | |
---|
| 351 | ```` |
---|
| 352 | $ npm install tv4 |
---|
| 353 | ```` |
---|
| 354 | |
---|
| 355 | #### bower |
---|
| 356 | |
---|
| 357 | ```` |
---|
| 358 | $ bower install tv4 |
---|
| 359 | ```` |
---|
| 360 | |
---|
| 361 | #### component.io |
---|
| 362 | |
---|
| 363 | ```` |
---|
| 364 | $ component install geraintluff/tv4 |
---|
| 365 | ```` |
---|
| 366 | |
---|
| 367 | ## Build and test |
---|
| 368 | |
---|
| 369 | You can rebuild and run the node and browser tests using node.js and [grunt](http://http://gruntjs.com/): |
---|
| 370 | |
---|
| 371 | Make sure you have the global grunt cli command: |
---|
| 372 | ```` |
---|
| 373 | $ npm install grunt-cli -g |
---|
| 374 | ```` |
---|
| 375 | |
---|
| 376 | Clone the git repos, open a shell in the root folder and install the development dependencies: |
---|
| 377 | |
---|
| 378 | ```` |
---|
| 379 | $ npm install |
---|
| 380 | ```` |
---|
| 381 | |
---|
| 382 | Rebuild and run the tests: |
---|
| 383 | ```` |
---|
| 384 | $ grunt |
---|
| 385 | ```` |
---|
| 386 | |
---|
| 387 | It will run a build and display one Spec-style report for the node.js and two Dot-style reports for both the plain and minified browser tests (via phantomJS). You can also use your own browser to manually run the suites by opening [`test/index.html`](http://geraintluff.github.io/tv4/test/index.html) and [`test/index-min.html`](http://geraintluff.github.io/tv4/test/index-min.html). |
---|
| 388 | |
---|
| 389 | ## Contributing |
---|
| 390 | |
---|
| 391 | Pull-requests for fixes and expansions are welcome. Edit the partial files in `/source` and add your tests in a suitable suite or folder under `/test/tests` and run `grunt` to rebuild and run the test suite. Try to maintain an idiomatic coding style and add tests for any new features. It is recommend to discuss big changes in an Issue. |
---|
| 392 | |
---|
| 393 | ## Packages using tv4 |
---|
| 394 | |
---|
| 395 | * [chai-json-schema](http://chaijs.com/plugins/chai-json-schema) is a [Chai Assertion Library](http://chaijs.com) plugin to assert values against json-schema. |
---|
| 396 | * [grunt-tv4](http://www.github.com/Bartvds/grunt-tv4) is a plugin for [Grunt](http://http://gruntjs.com/) that uses tv4 to bulk validate json files. |
---|
| 397 | |
---|
| 398 | ## License |
---|
| 399 | |
---|
| 400 | The code is available as "public domain", meaning that it is completely free to use, without any restrictions at all. Read the full license [here](http://geraintluff.github.com/tv4/LICENSE.txt). |
---|
| 401 | |
---|
| 402 | It's also available under an [MIT license](http://jsonary.com/LICENSE.txt). |
---|