From c7b62aed916f5cd2974ed3bb8faffaf8f7353af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20L=C3=A9caud=C3=A9?= Date: Wed, 29 Aug 2018 12:20:04 -0400 Subject: [PATCH 1/3] JSON schema: add draft-06 support (via $schema keyword) --- nodes/core/parsers/70-JSON.js | 1 + 1 file changed, 1 insertion(+) diff --git a/nodes/core/parsers/70-JSON.js b/nodes/core/parsers/70-JSON.js index eb0bec63c..234a742c6 100644 --- a/nodes/core/parsers/70-JSON.js +++ b/nodes/core/parsers/70-JSON.js @@ -19,6 +19,7 @@ module.exports = function(RED) { const Ajv = require('ajv'); const ajv = new Ajv({allErrors: true, schemaId: 'auto'}); ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json')); + ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json')); function JSONNode(n) { RED.nodes.createNode(this,n); From 40d81358f4c3fed49d992e2a08c4f6a401ff2218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20L=C3=A9caud=C3=A9?= Date: Wed, 29 Aug 2018 13:36:28 -0400 Subject: [PATCH 2/3] JSON schema: perform validation when obj -> obj or str -> str --- nodes/core/parsers/70-JSON.js | 35 +++++++- test/nodes/core/parsers/70-JSON_spec.js | 105 ++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 3 deletions(-) diff --git a/nodes/core/parsers/70-JSON.js b/nodes/core/parsers/70-JSON.js index 234a742c6..bc5d0269a 100644 --- a/nodes/core/parsers/70-JSON.js +++ b/nodes/core/parsers/70-JSON.js @@ -30,6 +30,16 @@ module.exports = function(RED) { this.compiledSchema = null; var node = this; + + this.validateMessage = function(msg) { + if (this.compiledSchema(msg[node.property])) { + node.send(msg); + } else { + msg.schemaError = this.compiledSchema.errors; + node.error(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`, msg); + } + } + this.on("input", function(msg) { var validate = false; if (msg.schema) { @@ -66,7 +76,17 @@ module.exports = function(RED) { } catch(e) { node.error(e.message,msg); } } else { - node.send(msg); + // If node.action is str and value is str + if (validate) { + if (this.compiledSchema(JSON.parse(msg[node.property]))) { + node.send(msg); + } else { + msg.schemaError = this.compiledSchema.errors; + node.error(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`, msg); + } + } else { + node.send(msg); + } } } else if (typeof value === "object") { @@ -85,13 +105,22 @@ module.exports = function(RED) { RED.util.setMessageProperty(msg,node.property,JSON.stringify(value,null,node.indent)); node.send(msg); } - } catch(e) { node.error(RED._("json.errors.dropped-error")); } } else { node.warn(RED._("json.errors.dropped-object")); } } else { - node.send(msg); + // If node.action is obj and value is object + if (validate) { + if (this.compiledSchema(value)) { + node.send(msg); + } else { + msg.schemaError = this.compiledSchema.errors; + node.error(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`, msg); + } + } else { + node.send(msg); + } } } else { node.warn(RED._("json.errors.dropped")); } diff --git a/test/nodes/core/parsers/70-JSON_spec.js b/test/nodes/core/parsers/70-JSON_spec.js index ba913b1e7..4f6e4beb2 100644 --- a/test/nodes/core/parsers/70-JSON_spec.js +++ b/test/nodes/core/parsers/70-JSON_spec.js @@ -265,6 +265,23 @@ describe('JSON node', function() { }); }); + it('should pass an object if provided a valid object and schema and action is object', function(done) { + var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]}, + {id:"jn2", type:"helper"}]; + helper.load(jsonNode, flow, function() { + var jn1 = helper.getNode("jn1"); + var jn2 = helper.getNode("jn2"); + jn2.on("input", function(msg) { + should.equal(msg.payload.number, 3); + should.equal(msg.payload.string, "allo"); + done(); + }); + var obj = {"number": 3, "string": "allo"}; + var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}}; + jn1.receive({payload:obj, schema:schema}); + }); + }); + it('should pass a string if provided a valid object and schema', function(done) { var flow = [{id:"jn1",type:"json",wires:[["jn2"]]}, {id:"jn2", type:"helper"}]; @@ -281,6 +298,22 @@ describe('JSON node', function() { }); }); + it('should pass a string if provided a valid JSON string and schema and action is string', function(done) { + var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]}, + {id:"jn2", type:"helper"}]; + helper.load(jsonNode, flow, function() { + var jn1 = helper.getNode("jn1"); + var jn2 = helper.getNode("jn2"); + jn2.on("input", function(msg) { + should.equal(msg.payload, '{"number":3,"string":"allo"}'); + done(); + }); + var jsonString = '{"number":3,"string":"allo"}'; + var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}}; + jn1.receive({payload:jsonString, schema:schema}); + }); + }); + it('should log an error if passed an invalid object and valid schema', function(done) { var flow = [{id:"jn1",type:"json",wires:[["jn2"]]}, {id:"jn2", type:"helper"}]; @@ -305,6 +338,78 @@ describe('JSON node', function() { }); }); + it('should log an error if passed an invalid object and valid schema and action is object', function(done) { + var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]}, + {id:"jn2", type:"helper"}]; + helper.load(jsonNode, flow, function() { + try { + var jn1 = helper.getNode("jn1"); + var jn2 = helper.getNode("jn2"); + var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}}; + var obj = {"number": "foo", "string": 3}; + jn1.receive({payload:obj, schema:schema}); + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "json"; + }); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.should.equal("json.errors.schema-error: data.number should be number, data.string should be string"); + logEvents[0][0].should.have.a.property('level',helper.log().ERROR); + done(); + } catch(err) { + done(err); + } + }); + }); + + it('should log an error if passed an invalid JSON string and valid schema', function(done) { + var flow = [{id:"jn1",type:"json",wires:[["jn2"]]}, + {id:"jn2", type:"helper"}]; + helper.load(jsonNode, flow, function() { + try { + var jn1 = helper.getNode("jn1"); + var jn2 = helper.getNode("jn2"); + var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}}; + var jsonString = '{"number":"Hello","string":3}'; + jn1.receive({payload:jsonString, schema:schema}); + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "json"; + }); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.should.equal("json.errors.schema-error: data.number should be number, data.string should be string"); + logEvents[0][0].should.have.a.property('level',helper.log().ERROR); + done(); + } catch(err) { + done(err); + } + }); + }); + + it('should log an error if passed an invalid JSON string and valid schema and action is string', function(done) { + var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]}, + {id:"jn2", type:"helper"}]; + helper.load(jsonNode, flow, function() { + try { + var jn1 = helper.getNode("jn1"); + var jn2 = helper.getNode("jn2"); + var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}}; + var jsonString = '{"number":"Hello","string":3}'; + jn1.receive({payload:jsonString, schema:schema}); + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "json"; + }); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.should.equal("json.errors.schema-error: data.number should be number, data.string should be string"); + logEvents[0][0].should.have.a.property('level',helper.log().ERROR); + done(); + } catch(err) { + done(err); + } + }); + }); + it('should log an error if passed a valid object and invalid schema', function(done) { var flow = [{id:"jn1",type:"json",wires:[["jn2"]]}, {id:"jn2", type:"helper"}]; From 4cdd7978cf5699ccab1f4ec6d03907cb66f1e166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20L=C3=A9caud=C3=A9?= Date: Wed, 29 Aug 2018 13:40:37 -0400 Subject: [PATCH 3/3] JSON schema: remove unused function --- nodes/core/parsers/70-JSON.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/nodes/core/parsers/70-JSON.js b/nodes/core/parsers/70-JSON.js index bc5d0269a..4e1e51e47 100644 --- a/nodes/core/parsers/70-JSON.js +++ b/nodes/core/parsers/70-JSON.js @@ -31,15 +31,6 @@ module.exports = function(RED) { var node = this; - this.validateMessage = function(msg) { - if (this.compiledSchema(msg[node.property])) { - node.send(msg); - } else { - msg.schemaError = this.compiledSchema.errors; - node.error(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`, msg); - } - } - this.on("input", function(msg) { var validate = false; if (msg.schema) {