Home

Awesome

controller-router

URL to controller, router

Basic example of router configuration:

var ControllerRouter = require('controler-router');

// Get router for provided routes
var router = new ControllerRouter({
  // '/' route
  '/': function () {
    console.log("Root!");
  },
  // '/foo' route
  'foo': function () {
    console.log("Foo!");
  },
  // '/foo/bar' route
  'foo/bar': function () {
    console.log("Foo, Bar!");
  },
  // '/lorem/*' dynamic route
  'lorem/[0-9][0-9a-z]+': {
    match: function (id) {
      if (id !== '0abc') return false;
        // for demo purposes, pass only '0abc'
        this.name = id;
      },
    controller: function () {
      console.log("Lorem, " + this.name + "!");
    }
  }
});

router.route('/'); // Calls "/" controller (logs "Root!") and returns route call event object
router.route('/foo/'); // "Foo!"
router.route('/not-existing/'); // Not found, returns false
router.route('/foo/bar/'); // "Foo, Bar!"
router.route('/lorem/elo'); // Not found, returns false
router.route('/lorem/0abc'); // "Lorem, 0abc!"

Installation

$ npm install controller-router

API

ControllerRouter constructor properties

ControllerRouter.ensureRoutes(routes)

Validates provided routes configuration, it is also used internally on router initialization

ControllerRouter initialization

new ControllerRouter(routes[, options])
var ControllerRouter = require('controller-router');

var router = new ControllerRouter({
  // .. routes configuration
});

ControllerRouter on initalizaton accepts routes map, and eventual options:

Routes map configuration

In routes map, key is a path, and value is a controller. Routes are defined as flat map, there are no nested route configurations.

####### Routes map: path keys

A valid path key is a series of tokens separated with / character. Where a token for typical static path is built strictly out of a-z, 0-9, - characters set.

We can also mix into path a dynamic path tokens, which we describe in regular expression format, but it is assumed that all tokens also resolve strictly to values built out of a-z, 0-9, - character set.

Internally engine naturally distinguish between static and dynamic tokens on basis of fact that regular expression will use characters out of basic set.

In addition to above, a / key is understood as root url.

Examples of static path keys:

Examples of dynamic path keys:

Routes for dynamic path keys, can be combined with static that override them. e.g. we may have configuration for user/[a-z]{3,10} and user/mark, and /user/mark url will be routed to user/mark configuration, as it has higher specifity for given path

####### Routes map: controller values

For static path keys, controllers may be direct functions e.g.:

'foo/bar': function () {
  // controller body
}

They can also be configured with objects which provide a controller property:

'foo/bar': {
  controller: function () {
    // controller body
  }
};

Two of above configurations are equal in meaning.

If path key contains dynamic tokens, then match function is required, and configuration must be configured as:

'lorem/[0-9][a-z0-9]{6}/foo/[a-z]{1,2}': {
  match: function (token1, token2) {
    if (!loremExists(token1) || !fooExists(token2)) {
      // while tokens matched pattern, no corresponding entities were found
      return false;
    }
    this.lorem = resolveLorem(token1);
    this.foo = resolve(token2);
    return true;
  },
  controller: function () {
    // controller body
    doSomethingWith(this.lorem, this.foo);
  }
};

match function would be invoked in same event context as controller, and arguments it receives is resolved tokens from url which match all route regexp tokens.

ControllerRouter instance properties

controllerRouter.route(path[, ...controllerArgs])

Resolves controller for given path, and if one is found, it is invoked. Additionally after a path argument, we can pass arguments for controller function (mind that those arguments won't be provided to eventual match function)

For each method call, a new event is created (as a plain object, or as an extension to provided at initialization eventProto object). It is used as a context for match and controller invocations, event object should be used as a transport for values that we resolve at match step, and want to access at controller step.

router method when invoked returns either false when no controller for given path was found, or in case of a valid route, a result object with following properties is returned:

If internally invoked controller function crashes, then conf and event objects, can be found as properties on error instance.

controllerRouter.routeEvent(event, path[, ...controllerArgs])

With routeEvent method we can force specific event (controller context) for given route call. Aside of that it behaves exactly as route method.

nestRoutes(path, routes[, match])

var nestRoutes = require('controller-router/nest');

var routes = {
  bar: function barController() { ... }
};

var nestedAgainstFoo = nestRoutes('foo', routes);
console.log(nestedAgainstFoo);
// { 'foo/bar': fuction barController() { ... } }

var nestedAgainstUser = nestRoutes('user/[0-9][a-z0-9]{6}', routes, function (userId) {
  this.user = resolveUser(userId);
});
console.log(nestedAgainsUser);
// { 'user/[0-9][a-z0-9]{6}/bar': {
//    match: function (userId) {...} ,
//    controller: function barController() { ... }
// } }

Returns new routes map, where each route is additionally nested against provided path. Provided nest path can contain regExp tokens, in such case also match function must be passed.

It's useful, when we have configured routes, which in some special cases we want to use against some nested route.

Available Extensions

controller-router on its own is a generic utility and doesn't provide functionalities which you would need for certain use cases. Following is a list of extensions which address specific scenarios:

Tests Build Status

$ npm test