cw-json-routing

0.1.6 • Public • Published

Express JSON Routes

Make routes much easier to use in MVC format. I've been searching for a while for a nodejs routing solution with a:

  • simple configuration,
  • super performance,
  • simple code,
  • MVC organization,
  • manage only routing, no other auto magic api creation
  • customizable
  • least possible dependency, which uses only underscore

This is: json-routes.

How It Works

The basic concepts. Create a json file with your routing config and add code logic in a external file called controller , creating an MVC style structure.

I followed the Expressjs 4 routing standards, helping the developer to manage the routes creation and project organization faster and in the standard synthax.

Proposed Structure

This is an example of the default proposed structure, you can customize and change as you prefer.

project root
├── controllers/
│   ├── IndexController.js
│   ├── AuthController.js
│   ├── UsersController.js
├── policy/
│   │   ├── AuthorizationPolicy.js
│   │   ├── mymiddleware.js
├── routes/
│   │   │   ├── auth.json
│   │   │   ├── users.json
│   │   │   ├── index.json
├── app.js/
├── package.json/
├── README.md/
  • Controller: contains the code's logic
  • Policy: contains the function called before the controller = middleware
  • Routes: contains all the *.json routing configuration. You can create as many *.json files as you need. By default, all routes within a file look up the corresponding controller (= modules = controllers = middleware) inside the controller's default directory ./controller (or within the directory specified by the user), which uses the following naming format: Route-name (without .json) + "Controller.js (the first letter must be capitalized)".

EXAMPLE: If you have a definition file called users.json, by default the route searches the controller UsersControllers.js. For routes auth.json all routes call the controller AuthController.js ecc.. ecc..

NOTE: this is a proposed structure but you can configure the module for your structure, you can change dir structure or add all routes in a single file.

Creating JSON Configuration file

The routing file is encoded in the JSON format and by default is in ./routes.

Router is created using this syntax:

{ "RoutePath" : {"verb": {options} } }

Example of extended config

{
   "routePath": {
    "VERB": {
      "route": "controller:method",
      "policy": [
        "controller:method",
      ]
    }
  },
 
  "/admin": {
    "GET": {
      "route": "action",
      "policy": [
        "./demo/policycustom/test:check",
        "test:all",
        "subfolder/test2:index"
      ]
    },
    "POST": {
      "route": "./mycustomfolder/controllername:index",
      "policy": [
        "./demo/policycustom/test:check",
        "test:all",
        "subfolder/test2:index"
      ],
      "cors":true
    }
  },
 
 
 ...
  more routes
}

RoutePath

This is the routing path and it follows the express4 standard routing. You can use jolly character and other type syntax /admin*, /admin/:name etc. etc.;

Verb

Relates to the call verb and can assume any valid http verbs like GET, POST, PUT, DELETE etc etc. You can add more verbs for a single routePath:

{
"/admin": {
    "GET": {
      "route": "action",
      "policy": [
        "./demo/policycustom/test:check",
        "test:all",
        "subfolder/test2:index"
      ]
    },
    "POST": {
      "route": "action",
      "policy": [
        "test:all",
      ]
    }
 
}

/admin has GET and POST verbs.

Route

Relates to file:method to call a route address.

By default, the routing search controller file inside the default controller directory is: ./controlles, and you can change it using the global options explained in this document.

If the controller is not set, the routing will search a file called with the same name as the json file, with "Controller" as suffix.

Example: If you have a definition file called users.json, by default the route searches the controller UsersControllers.json. For routes auth.json all routes call the controller AuthController.js etc.. etc..

Summarize route params

If you omit the route params, the system routing assumes you have a default route controller path/name and a method called "index".

If you add only a parameter, it assumes that the controller is in the default directory with standard name nameController.js , and the parameter is the method that should be called. example route: "testall"

If the route params contain both values controllername:method (user:index) it will search the controller using the default directory path structured as controller name followed by method. For example, route: "user:index" searches for a controller called user.js with method index.

If you need to call a controller in a subfolder, simply add the path before the controller name. Example route: "/afolder/user:index", fire ./controller/afolder/user.js with method index.

If you need to call a controller starting to your project root simply add . before the path. Example route: "./lib/user:index", fire ./lib/user.js with method index.

Policy

Is a module/function called before the controller (= middleware), by default it calls a file in ./policy named as you set in parameters "fileName" and a function named as you set in "functionName".

Example: policy: "auth/index" calls ./policy/auth.js and method index

The syntax is the same as route params

It can be a string for a single policy or an array for multiple policy files.

CORS

Enable or disable Cross-origin resource sharing. default is false and disabled.

Regex

You can set a regex to validate your route, however I discourage using it. Instead, I prefer to add this logic in the controller for better code speed.

{
"/admin": {
    "GET": {
      "route": "action",
      "policy": [
        "./demo/policycustom/test:check",
        "test:all",
        "subfolder/test2:index"
      ],
      "regex" : true | false
    }
 
 
}

Init Module

Configure the routing modules in your main js file, as any other nodes modules.

// Includes
var express     = require('express');
var app         = express();
var routes      = require('cw-json-routing'); // add module
 
...
 
// your code..
app.set(...);
app.use(...);
 
// this is the magic!
routes(app); //init modules
 

Change default Options

When you initialize the module, you can specify a few options to customize the directory structure. All are listed below with the default values. An explanation follows.

your main.js file

// Includes
var express     = require('express');
var app         = express();
var routes      = require('cw-json-routing'); // add module
 
// your code..
app.set(...);
app.use(...);
 
//define routes default options
var routeOptions = {
    routesPath      : "./routes",
    controllerPath  : "./controllers",
    policyPath      : "./policy",
    cors            : false,
    displayRoute    : true,
    defaultAction   : "index"
}
 
//init routes
routes(app, routeOptions);
  • routesPath : the path to your routes folder. Default ./routes
  • controllerPath : the path to your controller folder. Default ./controllers
  • policyPath : the path to your policy folder. Default ./policy
  • cors : enable cross origin resource sharing for all routes. (more cors options coming soon..). Default false
  • displayRoute : display in console loading route info, default true.
  • defaultAction : the function called in route if not specified. It's not so useful, but it's here!.Default index

If you omit routeOptions or some params it use defaults values.

Change json file Global Options

If you need to change options for all routes only for a specific *.json file, you can set in your file the key GLOBAL as in the following example:

user.json

{
  "GLOBAL": {
    "controllerPath": "./customdir",
    "controller": "test",
    "policyPath":"./lib",
    "policy":["config:setall","config:connection"],
    "baseUrl":"/user"
  },
   "/create": {
    "PUT": {
      "route": "index",
      "policy": [
        "auth:check",
        "auth:adduserparams"
      ]
    }
  }
 
}

Example: route controller is ./customdir/UserController.js

  • controllerPath: set a controller path for all routing file
  • controller: set a custom name controller for all routing file
  • policyPath: set a custom base policy dir for all rout
  • policy: is an array of policy file:action to fire before controller
  • baseUrl: is a base path for all url routes in file. Example, inside a file all routes start with /api/*, i can set base url as /api. Now all file routes start with /api. If i have a routes /users, it fired when user called /api/users

NOTE: the key "GLOBAL" must be uppercase.

Full extended example

app.js

var express = require('express')
    , app = express()
    , port = process.env.PORT || 3000
    , routing = require('./lib/route');
 
/**
 * global options for routing
 *
 * set all file inside /api/* for a more cleaner code
 */
var routeOptions = {
    routesPath: "./api/routes"
    , controllersPath: "./api/controllers"
    , policyPath: './api/policy'
    , cors: false
};
 
/**
 * init cw-json-routing
 */
routing(app, routeOptions);
 
/**
 * standard express 4 routing
 * yes.. you can use both routing together if you need
 */
var router = express.Router();
router.get('/express/', function (req, res) {
    res.send(' this is a standard routing ');
});
app.use('/', router);
 
/**
 * server start
 *
 * @type {http.Server} 
 */
var server = app.listen(port, function () {
    console.log('Listening on port %d', server.address().port);
});

This is the main file, we set routing and add global setting to use ./api as root directory

./api/routes/users.json

{
   "/banned": {
    "GET": {
      "route": "bannedCustom:index",
      }
  },
   "/user": {
    "GET": {
      "route": "find",
      "policy": [
        "auth:check",
        "auth:adduserparams"
      ]
    },
     "PUT": {
      "route": "create",
      "policy": [
        "auth:check",
      ]
    }
  }
 
}

define the routes

./api/controllers/UsersController.js

exports.index = function(req,res,next) {
    res.send(' index routes ');
};
 
exports.create = function(req,res,next) {
    res.send(' create routes params:'+req.params.name);
};

a basic controller logic

./api/controllers/bannedCustom.js

exports.getbanned = function(req,res,next) {
    res.send(' custom controller name ');
};

this is the controller with custom name

./api/policy/auth.js

exports.check = function(req,res,next) {
    if (!req.session.isLogged){
         return  res.redirect('http://'+req.hostname+":3000/403");
    }
    next();
};

Let me explain this policy: it checks if a user is logged, else set a redirect, so we can use the middleware to check ACL, authorization or get/set global vars, and this is very useful.

Create a Policy File and Pass vars to controller

We encourage to use standard tecnique for best performance: use middleware. using the full example described below we can create a standard policy file to attach a global var using req

./api/policy/auth.js

exports.getbanned = function(req,res,next) {
    if (!req.session.isLogged){
         return  res.redirect('http://'+req.hostname+":3000/403");
    }
    //use req
    req.session.lastPing = new Date();
    next();
};

Read the value in the controller or policy

./api/controllers/bannedCustom.js

exports.getbanned = function(req,res,next) {
    res.send(' custom controller name, middleware loaded at: '+req.session.lastPing);
};

Case: using middleware

A special case: if we want to add an authentication before some route, take a look at this example:

{
 
 "/admin*": {
    "GET": {
      "route": "./policy/auth:check",
     },
    "POST": {
      "route": "auth:check",
     },
    "PUT": {
      "route": "auth:check",
     },
    "DELETE": {
      "route": "auth:check",
    },
  },
 
   "/admin/dashboard": {
    "GET": {
      "route": "getItem",
      }
  },
   "/admin/user": {
    "GET": {
      "route": "find",
    },
     "PUT": {
      "route": "create",
    }
  }
 
}}

All admin* route calls the controller auth, so now auth:check is executed before all admin* controller and it becomes a policy (=middleware) and for a clear structure i put the file in policy dir.

An alternative example use the global file option:

{
 "GLOBAL": {
    "policy":["auth:check"],
    "baseUrl":"/admin"
  },
  
   "/dashboard": {
    "GET": {
      "route": "getItem",
      }
  },
   "/user": {
    "GET": {
      "route": "find",
    },
     "PUT": {
      "route": "create",
    }
  }
 
}}

Changelog 0.1.6

  • added extra option for supporting custom global policy

Changelog 0.1.5

  • added extra option for supporting custom global policy

Changelog 0.1.0

  • minor fix

Changelog 0.1.0

  • removed not working cors features for file definition and route... working on it.. cors for global setting work good.

Changelog 0.0.27

  • improve log info

Changelog 0.0.26

  • add defaultAction, not so useful, but it's here!.
  • start cleaning code
  • add CORS Global file options, to enable CORS only in specific *.json routes
  • add CORS for specific routes.
  • route log info display CORS status

Changelog 0.0.25

  • improve route info on load, it can disabled with global options "displayRoute:false"

Changelog 0.0.24

  • initial CORS support (look at "Change default Options"), more CORS options coming soon...

Changelog 0.23

  • fix url union for windows platform

Changelog 0.0.20

  • fix policy string is not added if global policy is set
  • working test

Changelog 0.0.19

  • add Global base Url

Changelog 0.0.17

  • fix default route
  • add mre error check

Changelog 0.0.15

  • add goblal file policy (=middleware)

Changelog from version 0.0.13

  • No longer compatible with <0.13 version
  • new json syntax

Package Sidebar

Install

npm i cw-json-routing

Weekly Downloads

3

Version

0.1.6

License

MIT

Last publish

Collaborators

  • satish-ambab