add json2xml plugin
diff --git a/json2xml/index.js b/json2xml/index.js new file mode 100644 index 0000000..2b78e72 --- /dev/null +++ b/json2xml/index.js
@@ -0,0 +1,194 @@ +'use strict'; +/** + * This plugin accumulates data chunks from the client into an array + * property on the request or response, concats them on end. Then + * transforms the request or response based on 'accept' or 'content-type' + * headers. + * + * If the HTTP verb is GET and the Accept type does not match the + * response type, the plugin will attempt to transform it (from + * xml to json or vice versa). + * + * If the HTTP verb is NOT GET then the content-type is used. If the + * content-type is set to 'json', then an attempt is made to transform to + * 'xml' and vice-versa. + * + * This plugin can be disabled by sending the 'x-apigee-json2xml' http + * header. + * + * Users should be aware that buffering large requests or responses in + * memory can cause Apigee Edge Microgateway to run out of memory under + * high load or with a large number of concurrent requests. So this plugin + * should only be used when it is known that request/response bodies are small. + */ + +var debug = require('debug')('plugin:json2xml'); +//library to convert json to xml +var js2xmlparser = require("js2xmlparser"); +//library to convert xml to json +var parseString = require("xml2js").parseString; +var util = require("util"); + +module.exports.init = function (config, logger, stats) { + + //initialize the variables to false + + //variables to control whether request and/or response transformation should take place + var requestXML = false; + var requestJSON = false; + var responseJSON = false; + var responseXML = false; + //use these variables to determine the content type of response sent by target server + var responseIsXML = false; + var responseIsJSON = false; + //flag to control whether transfornation should take place + var disable = false; + + //method to accumulate responses + function accumulateResponse(res, data) { + debug('plugin accumulateResponse'); + if (!res._chunks) res._chunks = []; + res._chunks.push(data); + } + + //method to accumulate requests + function accumulateRequest(req, data) { + debug('plugin accumulateRequest'); + if (disable) return; + if (!req._chunks) req._chunks = []; + req._chunks.push(data); + } + + return { + + onrequest: function(req, res, next) { + debug('plugin onrequest'); + var method = req.method.toLowerCase(); + var acceptType = req.headers['accept']; + var contentType = req.headers['content-type']; + + if (req.headers['x-apigee-json2xml-disable']) disable = true; + + debug("accept header: " + acceptType); + debug("content-type header: " + contentType); + + //if plugin is disabled don't process headers. + if (!disable) { + if (method === "get" && acceptType === "application/xml") { + responseXML = true; + } else if (method === "get" && acceptType === "application/json") { + responseJSON = true; + } else if (method !== "get" && contentType === "application/json") { + requestJSON = true; + responseJSON = true; + } else if (method !== "get" && contentType === "application/xml") { + requestXML = true; + responseXML = true; + } + } + + debug("requestJSON flag is " + requestJSON); + debug("responseJSON flag is " + responseJSON); + + debug("requestXML flag is " + requestXML); + debug("responseXML flag is " + responseXML); + + debug("plugin disabled: " + disable); + + next(); + }, + // indicates start of target response + // response headers and status code should be available at this time + onresponse: function(req, res, next) { + debug('plugin onresponse'); + //nothing to do on response + next(); + }, + // + ondata_request: function(req, res, data, next) { + debug('plugin ondata_request'); + if (data && data.length > 0 && disable == false) accumulateRequest(req, data); + next(null, null); + }, + // + // + ondata_response: function(req, res, data, next) { + debug('plugin ondata_response'); + if (data && data.length > 0 && disable == false) accumulateResponse(res, data); + next(null, null); + }, + // + onend_request: function(req, res, data, next) { + debug('plugin onend_request'); + if (data && data.length > 0 && disable == false) accumulateRequest(res, data); + var content = null; + if(req._chunks && req._chunks.length) { + content = Buffer.concat(req._chunks); + } + delete req._chunks; + + //if pugin is disabled, don't do anything + if (!disable) { + if (requestJSON) { + //the request needs to be transformed to xml before sending to + //the target server. + + //set request content type. + req.setHeader('Content-Type', 'application/xml'); + next(null, js2xmlparser.parse("Root",JSON.parse(content))); + } else if (requestXML) { + //set request content type. + req.setHeader('Content-Type', 'application/json'); + parseString(content.toString(), function(err, js){ + if (err) next (err); + next(null, JSON.stringify(js)); + }); + } else { //do nothing + next(null, content); + } + } else { + next(null, content); + } + }, + // + onend_response: function(req, res, data, next) { + debug('plugin onend_request'); + if (data && data.length > 0 && disable == false) accumulateResponse(res, data); + + var contentType = res.getHeader('content-type'); + if (contentType === "application/xml") { + responseIsXML = true; + } else if (contentType === "application/json") { + responseIsJSON = true; + } + + debug("responseIsJSON flag is " + responseIsJSON); + debug("responseIsXML flag is" + responseIsXML); + + + var content = null; + if(res._chunks && res._chunks.length) { + content = Buffer.concat(res._chunks); + } + delete res._chunks; + + //if disabled don't do anything. + if (!disable) { + if (responseXML && responseIsJSON) { + res.setHeader('Content-Type', 'application/xml'); + next(null, js2xmlparser.parse("Root",JSON.parse(content))); + } else if (responseJSON && responseIsXML) { + res.setHeader('Content-Type', 'application/json'); + parseString(content.toString(), function(err, js){ + if (err) next (err); + next(null, JSON.stringify(js)); + }); + } else { + next(null, content); + } + } else { + next(null, content); + } + } + }; +} \ No newline at end of file
diff --git a/json2xml/package.json b/json2xml/package.json new file mode 100644 index 0000000..52013ed --- /dev/null +++ b/json2xml/package.json
@@ -0,0 +1,24 @@ +{ + "name": "edgemicro-json2xml", + "version": "1.0.0", + "description": "This plugin transforms JSON to XML and vice versa based on the Accept and Content-Type http headers", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "srinandan", + "license": "Apache 2.0", + "dependencies": { + "debug": "^2.2.0", + "js2xmlparser": "^2.0.2", + "xml2js": "^0.4.17" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/apigee/microgateway-plugins.git" + }, + "bugs": { + "url": "https://github.com/apigee/microgateway-plugins/issues" + }, + "homepage": "https://github.com/apigee/microgateway-plugins#readme" +}