UNPKG

json-routing-v-ks

Version:

Extended version of Giorgio Modoni JSON ROUTING

537 lines (429 loc) 13.6 kB
var _ = require('underscore') , path = require('path'); /** * Parse JSON file config and create routes * * @param app * @param options */ module.exports = function (app, options) { var jsonFileName = path.join(options.basePathJson, options.routeName + '.json') , json = loadJsonFile(jsonFileName) , basePathController = options.basePathController , basePathPolicy = options.basePathPolicy , controller = getControllerName(options.routeName) , globalMiddleware = [] , baseUrl = "" , cors = options.cors; //set global file options setFileGlobalParams(json); // start parsing json file main(); /** * main job * parse json file */ function main() { for (uri in json) { // go to parse verbs parseRoutes(uri, json); } } /** * parse verbs * @param uri * @param json */ function parseRoutes(uri, json) { for (key in json[uri]) { // route defaults var data = json[uri] , verb = key.toLowerCase() , action = "index" , middleware = null , regex = false , params = data[key] , pattern = baseUrl + uri , controllerPath , route , routes , defaultRoute = controller + ":" + options.defaultAction; // set default route if (_.isUndefined(params.route)) params.route = defaultRoute; if (_.isUndefined(params.cors)) params.cors = cors; route = parseRoute(params.route); controllerPath = getControllerPath(route[0]); if (_.indexOf(options.excludeRoutes, pattern) === -1) { if (!_.isUndefined(options.customGlobalPolicy)) { if (typeof(options.customGlobalPolicy) == 'string') { options.customGlobalPolicy = [options.customGlobalPolicy]; } if (!_.isUndefined(params.policy)) { params.policy = params.policy.concat(options.customGlobalPolicy); } else { params.policy = options.customGlobalPolicy; } } } middleware = getMiddleware(params.policy); //check cors /* if (params.cors) { middleware = addCors(middleware); } */ regex = params.regex; routes = require(controllerPath); // get handler handler = routes[route[1]]; if (regex) pattern = addRegex(regex, pattern); addRoute(middleware, verb, pattern, handler,params.cors); } } function loadJsonFile() { try { return require(jsonFileName); } catch (ex) { console.log('\x1b[31m *** ROUTING FILE DEFINITION ERROR :' + jsonFileName + '\x1b[0m'); console.log('\x1b[31m All routes inside this file are not loaded, please check json syntax!\x1b[0m'); return true; } } /** * Inject middleware cors response * * @param mdlw * @returns {*} */ function addCors(mdlw) { //exit if cors disabled /* if (!cors) { return mdlw; } */ //cors is required //no middleware, normalize as null array if (_.isNull(mdlw)) { mdlw = []; } //TODO var override, need to be changed for clean code //exist a middleware pass as string, normalize as array if (_.isString(mdlw)) { mdlw = [mdlw]; } if (_.isArray(mdlw)) { // console.log('*****array' + mdlw.length); mdlw.push([function (req, res, next) { // console.log('cors array'); res.header("Access-Control-Allow-Origin", "*"); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With'); // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); // intercept OPTIONS method if ('OPTIONS' == req.method) { res.send(200); } else { next(); } }]); return mdlw; } console.log('impossible!!'); return mdlw; } /** * create routes * * @param middleware * @param verb * @param pattern * @param handler */ function addRoute(middleware, verb, pattern, handler,corsRoute) { try { if (middleware) { app[verb](pattern, middleware, handler); } else { app[verb](pattern, handler); } if (options.displayRoute) { displayRoutes(pattern, verb, 1, null,corsRoute); } } catch (ex) { displayRoutes(pattern, verb, 0, ex,corsRoute); /* console.log('\x1b[31m*** ROUTIG ERROR: ' + pattern + '\x1b[0m'); console.log('file: ' + jsonFileName); console.log('verb: ' + verb); console.log('error:' + ex); console.log('\x1b[31m****************\x1b[0m'); */ } } /** * Verbose log * * @param pattern * @param verb * @param status * @param err * @param corsRoute */ function displayRoutes(pattern, verb, status, err,corsRoute) { // set cors status var corsStatus = ' - \x1b[0mCORS: \x1b[32mOFF\x1b[0m'; if (corsRoute) { corsStatus = ' - \x1b[0mCORS: \x1b[31mON\x1b[0m'; } if (status) { console.log('\x1b[32m* \x1b[0mRoute: \x1b[34m' + pattern + ' - \x1b[35m' + verb.toUpperCase() + '\x1b[0m - file:\x1b[34m' + options.routeName + corsStatus + ' - Status:\x1b[32m OK ' + '\x1b[0m'); } else { console.log('\x1b[31m* \x1b[0mRoute: \x1b[34m' + pattern + ' - \x1b[35m' + verb.toUpperCase() + '\x1b[0m - file:\x1b[34m' + options.routeName + corsStatus + ' - Status:\x1b[31m KO ' + '\x1b[0m'); console.log(' ' + err); console.log(' filePath: ' + jsonFileName); console.log('\x1b[0m'); } } /** * return array * [0] action * [1] controller * * @param routeParams * @returns {*} */ function parseRoute(routeParams) { var result = []; // case no param is passed if (_.isUndefined(routeParams)) { result[0] = controller; result[1] = 'index'; return result; } var arrayParams = routeParams.split(':'); // params is passed only with action if (arrayParams.length == 1) { result[0] = controller; result[1] = routeParams; return result; } // all params return arrayParams; } /** * return controller path * if controller start with "." it start from project root * else use default dir * * @param controller * @returns {*} */ function getControllerPath(controller) { if (startWith(controller, '.')) { // return dir from root project return path.join(options.processdir, controller + '.js'); } // default dir return path.join(basePathController, controller + '.js'); } /** * get middlewarePath * * @param middleware * @returns {string} */ function getMiddlewarePath(middleware) { if (startWith(middleware, '.')) { // return dir from root project return path.join(options.processdir, middleware + '.js'); } // default dir return path.join(basePathPolicy, middleware + '.js'); } /** * return all middleware * * @param routeMiddleware * @returns {*} */ function getAllMiddleWare(routeMiddleware) { if (globalMiddleware.length > 0) { // fix if policy is string and global array if (_.isString(routeMiddleware)) { routeMiddleware = [routeMiddleware]; } return _.union(globalMiddleware, routeMiddleware); } return routeMiddleware; } /** * Parse middleware * check if is string or array and parse it * * @param input * @returns {*} */ function getMiddleware(input) { var mdlw = getAllMiddleWare(input); if (_.isString(mdlw)) { var items = []; items.push(parseMiddleware(mdlw)); return items; } else if (_.isArray(mdlw)) { var items = []; mdlw.forEach(function (item) { items.push(parseMiddleware(item)); }); return items; } return null; } /** * Parse middleware * * @param input * @returns {*} */ function parseMiddleware(input) { var parts = input.split(':'); // prevent malformed policy routes if (parts.length != 2) error(uri, "malformed json middleware"); var middlewareFile = getMiddlewareFile(parts[0]); var middleware = require(middlewareFile); return middleware[parts[1]]; } /** * return middleware path * * @param fileName * @returns {string} */ function getMiddlewareFile(fileName) { if (startWith(fileName, '.')) { return path.join(options.processdir, fileName + '.js'); } return path.join(basePathPolicy, fileName + '.js'); } /** * check if a string start with a value * * @param value * @param char * @returns {boolean} */ function startWith(value, char) { if (value.substring(0, 1) == char) { return true; } return false; } /** * check for json global params * * @param json * @returns {boolean} */ function checkGlobalVars(json) { if (_.isUndefined(json.GLOBAL)) { return false; } return true; } /** * override Global default params with Global file params * file if present * * @param json * @returns {boolean} */ function setFileGlobalParams(json) { if (!checkGlobalVars(json)) { return true } if (checkGlobalVars(json)) { //check controllerPath if (json.GLOBAL.hasOwnProperty('controllerPath')) { basePathController = path.join(options.processdir, json.GLOBAL.controllerPath); } // check controller Name if (json.GLOBAL.hasOwnProperty('controller')) { controller = json.GLOBAL.controller; } // check policy Path if (json.GLOBAL.hasOwnProperty('policyPath')) { basePathPolicy = path.join(options.processdir, json.GLOBAL.policyPath); } // check global policy and add it if (json.GLOBAL.hasOwnProperty('policy')) { if (_.isString(json.GLOBAL.policy)) { globalMiddleware.push(json.GLOBAL.policy); } else { globalMiddleware = json.GLOBAL.policy; } } // check global file Base Url if (json.GLOBAL.hasOwnProperty('baseUrl')) { baseUrl = json.GLOBAL.baseUrl; } // check cors if (json.GLOBAL.hasOwnProperty('cors')) { cors = json.GLOBAL.cors; } // sanitize json route removing global setting delete json.GLOBAL; } return true; } /** * cerate a valid route if regex is true * * @param regex * @param pattern * @returns {*} */ function addRegex(regex, pattern) { // process RegEx! if (regex) { var regexPattern = pattern; var flags = ""; // pull apart regex patten from the flags if (pattern.indexOf("/") != -1) { var regexParts = pattern.split('/'); flags = regexParts.pop(); // check to see if we need to strip off a starting slash if (regexParts[0].trim() == "") { regexParts.shift(); } regexPattern = regexParts.join("/"); } return new RegExp(regexPattern, flags); } return pattern; } /** * controller name is composed: * route name capitalizzed + Controller * route = "ping" * controller = "PingController" * suffix ".js" is added later * * @param string * @returns {string} */ function getControllerName(string) { return string.charAt(0).toUpperCase() + string.slice(1) + 'Controller'; } }; /** * set errors * * @param uri * @param reason */ /* function error(uri, reason) { throw new Error("For " + uri + " " + reason); } */