controller-router

3.9.3 • Public • Published

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:

  • eventProto - Prototype for route events. If provided, then each event, will be an instance that inherits from this object. For more information about event object, see Handling of router function section.
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:

  • / - root url, matches strictly / route
  • foo - matches /foo or /foo/ route
  • foo/bar/elo - matches /foo/bar/elo or /foo/bar/elo/ route

Examples of dynamic path keys:

  • [a-z]{3} - matches e.g. /abc /zws/ /aaa/, won't match e.g. /ab0 or /abcd
  • user/[0-9][a-z0-9]{6} - matches e.g. /user/0asd34d or /user/7few232 route
  • lorem/[0-9][a-z0-9]{6}/foo/[a-z]{1,2} - matches e.g. /lorem/0asd34d/foo. or /user/7few232 route

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:

  • conf a route configuration for chosen path (as it's provided on routes object)
  • event, an event for given router call
  • result a result value as returned by invoked controller

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:

  • post-controller-router - Router dedicated for update requests (e.g. form submissions in browsers, or POST requests on server-side)
  • site-tree-router - A view engine router (to switch between pages in response to url changes in address bar)

Tests Build Status

$ npm test

Readme

Keywords

Package Sidebar

Install

npm i controller-router

Weekly Downloads

1

Version

3.9.3

License

MIT

Last publish

Collaborators

  • medikoo