Skip to content

Commit bd68651

Browse files
committed
Add support for multiple versions of JSON Schema
See https://ajv.js.org/json-schema.html#json-schema-versions Fix #8
1 parent 2ff44d8 commit bd68651

File tree

6 files changed

+81
-10
lines changed

6 files changed

+81
-10
lines changed

.editorconfig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ indent_style = tab
1313
indent_style = tab
1414

1515
[*.json]
16-
indent_size = 2
17-
indent_style = space
16+
indent_style = tab
1817

1918
[*.md]
2019
indent_size = 4

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ Output:
275275

276276
* *Context*: Node-RED node, or command line with `node ./index.js json-multi-schema-validator`
277277
* *Purpose*: Ability to validate a JSON observation (e.g. one of the FIWARE NGSI types) on the fly against a specified JSON Schema URL. Schemas are automatically downloaded and cached the first time they are needed.
278+
* *Configuration*: A `schemaVersion` property indicating which [version of JSON Schema version](http://json-schema.org/specification.html). See the [Ajv documentation](https://ajv.js.org/json-schema.html#json-schema-versions) for technical details.
278279
* *Input*: A JSON observation (e.g. one of the FIWARE NGSI types) in the `msg.payload` property, and the corresponding JSON Schema URL on the `msg.schemaUrl` property (coming from json-multi-schema-resolver).
279280
* If no `msg.schemaUrl` is provided, no validation is performed.
280281
* *Output*: The unmodified JSON observation in the `msg.payload` property, the used schema in the `msg.validUrl` (if any validation was performed), and potential validation errors in the `msg.error` property.
@@ -312,7 +313,7 @@ The JSON input messages must each be on one single line, and wrapped into a Node
312313

313314
```sh
314315
echo '{"payload":{"id":"TA120-T246177-NoiseLevelObserved-2018-09-17T07:01:09.000000Z","type":"NoiseLevelObserved","LAeq":48.6,"dateObservedFrom":"2018-09-17T07:01:09.000000Z","dateObservedTo":"2018-09-17T07:01:09.000000Z","location":{"coordinates":[24.985891,60.274286],"type":"Point"}},"error":false,"transformUrl":"https://raw.githubusercontent.com/alexandrainst/node-red-contrib-json-multi-schema/master/examples/Cesva-TA120-to-NoiseLevelObserved.jsonata.js","schemaUrl":"https://smart-data-models.github.io/data-models/specs/Environment/NoiseLevelObserved/schema.json"}' | \
315-
node ./index.js json-multi-schema-validator | \
316+
node ./index.js json-multi-schema-validator --schemaVersion='\"draft-2019-09\"' | \
316317
jq .
317318
```
318319

json-multi-schema-validator.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
color: '#00B4FF',
66
defaults: {
77
name: { value: '' },
8+
schemaVersion: { value: 'draft-07' },
89
},
910
inputs: 1,
1011
outputs: 1,
@@ -20,6 +21,16 @@
2021
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
2122
<input type="text" id="node-input-name" placeholder="Name" />
2223
</div>
24+
<div class="form-row">
25+
<label for="node-input-schemaVersion"><i class="fa fa-flag"></i> JSON Schema version</label>
26+
<select id="node-input-schemaVersion">
27+
<option value="draft-07">draft-07 (default)</option>
28+
<option value="draft-2019-09">draft-2019-09 (newer but slower) + draft-07</option>
29+
<option value="draft-2020-12">draft-2020-12 (newest, not backwards compatible)</option>
30+
<option value="draft-06">draft-06 (obsolete) + draft-07</option>
31+
<option value="draft-04">draft-04 (obsolete, deprecated)</option>
32+
</select>
33+
</div>
2334
</script>
2435

2536
<script type="text/x-red" data-help-name="json-multi-schema-validator">
@@ -29,4 +40,10 @@
2940
<li>The content of <code>msg.payload</code> is unchanged. If no <code>msg.schemaUrl</code> is provided, no validation is performed.</li>
3041
<li>Errors are returned on <code>msg.error</code></li>
3142
</ul>
43+
<h3>Options</h3>
44+
<dl>
45+
<dt>schemaVersion</dt>
46+
<dd>Version of <a href="http://json-schema.org/specification.html">JSON Schema</a> to use</dd>
47+
<dd>See the <a href="https://ajv.js.org/json-schema.html#json-schema-versions">documentation from the underlying library</a></dd>
48+
</dl>
3249
</script>

json-multi-schema-validator.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66

77
// Ajv: Another JSON Schema Validator
8-
const Ajv = require('ajv').default;
98
const addFormats = require('ajv-formats').default;
109
const util = require('util');
1110

@@ -21,11 +20,48 @@ module.exports = RED => {
2120

2221
const jsonCache = require('./json-cache.js')(node);
2322

24-
const ajv = new Ajv({
23+
let ajv;
24+
const opts = {
2525
allErrors: true, // TODO: Make a parameter
2626
loadSchema: jsonCache.loadAsync,
2727
messages: true, // TODO: Make a parameter
28-
});
28+
};
29+
30+
// http://json-schema.org/specification.html
31+
// https://ajv.js.org/json-schema.html#json-schema-versions
32+
switch (config.schemaVersion) {
33+
case 'draft-2020-12': {
34+
const Ajv2020 = require('ajv/dist/2020');
35+
ajv = new Ajv2020(opts);
36+
break;
37+
}
38+
case 'draft-2019-09': {
39+
const Ajv2019 = require('ajv/dist/2019');
40+
ajv = new Ajv2019(opts);
41+
const draft7MetaSchema = require('ajv/dist/refs/json-schema-draft-07.json');
42+
ajv.addMetaSchema(draft7MetaSchema);
43+
break;
44+
}
45+
case 'draft-06': {
46+
const Ajv = require('ajv');
47+
const draft6MetaSchema = require('ajv/dist/refs/json-schema-draft-06.json');
48+
ajv = new Ajv(opts);
49+
ajv.addMetaSchema(draft6MetaSchema);
50+
break;
51+
}
52+
case 'draft-04': {
53+
const Ajv = require('ajv-draft-04');
54+
ajv = new Ajv(opts);
55+
break;
56+
}
57+
case 'draft-07':
58+
default: {
59+
const Ajv = require('ajv');
60+
ajv = new Ajv(opts);
61+
break;
62+
}
63+
}
64+
2965
addFormats(ajv);
3066

3167
// Cache of validators for different schemas

package-lock.json

Lines changed: 16 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-red-contrib-json-multi-schema",
3-
"version": "1.5.2",
3+
"version": "1.6.0",
44
"description": "Generic JSON data pipeline tools, with dynamic transformation (using JSONata rules), resolving JSON Schema (using JSONata rules), and then validation (using JSON Schema). For Node-RED and for command-line.",
55
"main": "index.js",
66
"readmeFilename": "readme.md",
@@ -39,6 +39,7 @@
3939
},
4040
"dependencies": {
4141
"ajv": "^8.12.0",
42+
"ajv-draft-04": "^1.0.0",
4243
"ajv-formats": "^2.1.1",
4344
"jsonata": "^2.0.3",
4445
"node-fetch": "^2.6.11",
@@ -58,6 +59,9 @@
5859
"eslint_fix": "eslint --fix --ext .js,.html .",
5960
"fix": "npm run eslint_fix",
6061
"pretest": "npm run-script eslint",
61-
"test": "rm /tmp/schema.*.tmp.js ; printf '{\"payload\":{\"id\":\"TA120-T246177\",\"type\":\"Cesva-TA120\",\"NoiseLevelObserved\":{\"id\":\"TA120-T246177-NoiseLevelObserved-2018-09-17T07:01:09.000000Z\",\"sonometerClass\":\"1\",\"location\":{\"coordinates\":[24.985891,60.274286],\"type\":\"Point\"},\"measurand\":[\"LAeq | 48.6 | A-weighted, equivalent, sound level\"],\"dateObserved\":\"2018-09-17T07:01:09.000000Z\",\"LAeq\":48.6,\"type\":\"NoiseLevelObserved\"}}} \\n {\"payload\":{\"id\":\"TA120-T246183\",\"type\":\"Cesva-TA120\",\"NoiseLevelObserved\":{\"id\":\"TA120-T246183-NoiseLevelObserved-2018-09-17T07:01:15.000000Z\",\"sonometerClass\":\"1\",\"location\":{\"coordinates\":[24.9030921,60.161804],\"type\":\"Point\"},\"measurand\":[\"LAeq | 37.6 | A-weighted, equivalent, sound level\"],\"dateObserved\":\"2018-09-17T07:01:15.000000Z\",\"LAeq\":37.6,\"type\":\"NoiseLevelObserved\"}}}' | node ./index.js json-multi-schema-resolver --mappingsUrl='\"https://raw.githubusercontent.com/alexandrainst/node-red-contrib-json-multi-schema/master/examples/smart-data-transforms.json\"' | node ./index.js json-multi-schema-transformer | node ./index.js json-multi-schema-resolver --mappingsUrl='\"https://raw.githubusercontent.com/alexandrainst/node-red-contrib-json-multi-schema/master/examples/smart-data-models.json\"' | node ./index.js json-multi-schema-validator"
62+
"clean": "rm /tmp/schema.*.tmp.js",
63+
"draft-07": "printf '{\"payload\":{\"id\":\"TA120-T246177\",\"type\":\"Cesva-TA120\",\"NoiseLevelObserved\":{\"id\":\"TA120-T246177-NoiseLevelObserved-2018-09-17T07:01:09.000000Z\",\"sonometerClass\":\"1\",\"location\":{\"coordinates\":[24.985891,60.274286],\"type\":\"Point\"},\"measurand\":[\"LAeq | 48.6 | A-weighted, equivalent, sound level\"],\"dateObserved\":\"2018-09-17T07:01:09.000000Z\",\"LAeq\":48.6,\"type\":\"NoiseLevelObserved\"}}} \\n {\"payload\":{\"id\":\"TA120-T246183\",\"type\":\"Cesva-TA120\",\"NoiseLevelObserved\":{\"id\":\"TA120-T246183-NoiseLevelObserved-2018-09-17T07:01:15.000000Z\",\"sonometerClass\":\"1\",\"location\":{\"coordinates\":[24.9030921,60.161804],\"type\":\"Point\"},\"measurand\":[\"LAeq | 37.6 | A-weighted, equivalent, sound level\"],\"dateObserved\":\"2018-09-17T07:01:15.000000Z\",\"LAeq\":37.6,\"type\":\"NoiseLevelObserved\"}}}' | node ./index.js json-multi-schema-resolver --mappingsUrl='\"https://raw.githubusercontent.com/alexandrainst/node-red-contrib-json-multi-schema/master/examples/smart-data-transforms.json\"' | node ./index.js json-multi-schema-transformer | node ./index.js json-multi-schema-resolver --mappingsUrl='\"https://raw.githubusercontent.com/alexandrainst/node-red-contrib-json-multi-schema/master/examples/smart-data-models.json\"' | node ./index.js json-multi-schema-validator",
64+
"draft-2019-09": "printf '{\"payload\":{\"id\":\"TA120-T246177\",\"type\":\"Cesva-TA120\",\"NoiseLevelObserved\":{\"id\":\"TA120-T246177-NoiseLevelObserved-2018-09-17T07:01:09.000000Z\",\"sonometerClass\":\"1\",\"location\":{\"coordinates\":[24.985891,60.274286],\"type\":\"Point\"},\"measurand\":[\"LAeq | 48.6 | A-weighted, equivalent, sound level\"],\"dateObserved\":\"2018-09-17T07:01:09.000000Z\",\"LAeq\":48.6,\"type\":\"NoiseLevelObserved\"}}} \\n {\"payload\":{\"id\":\"TA120-T246183\",\"type\":\"Cesva-TA120\",\"NoiseLevelObserved\":{\"id\":\"TA120-T246183-NoiseLevelObserved-2018-09-17T07:01:15.000000Z\",\"sonometerClass\":\"1\",\"location\":{\"coordinates\":[24.9030921,60.161804],\"type\":\"Point\"},\"measurand\":[\"LAeq | 37.6 | A-weighted, equivalent, sound level\"],\"dateObserved\":\"2018-09-17T07:01:15.000000Z\",\"LAeq\":37.6,\"type\":\"NoiseLevelObserved\"}}}' | node ./index.js json-multi-schema-resolver --mappingsUrl='\"https://raw.githubusercontent.com/alexandrainst/node-red-contrib-json-multi-schema/master/examples/smart-data-transforms.json\"' | node ./index.js json-multi-schema-transformer | node ./index.js json-multi-schema-resolver --mappingsUrl='\"https://raw.githubusercontent.com/alexandrainst/node-red-contrib-json-multi-schema/master/examples/smart-data-models.json\"' | node ./index.js json-multi-schema-validator --schemaVersion='\"draft-2019-09\"'",
65+
"test": "npm run clean; npm run draft-07 && npm run draft-2019-09"
6266
}
6367
}

0 commit comments

Comments
 (0)