Skip to content
This repository has been archived by the owner on Jan 10, 2022. It is now read-only.

Core Routing

cliftonc edited this page Aug 3, 2011 · 11 revisions

Routing

The external view to routing was described in Calipso Router, explaining how the core library passes requests through to the module route function using the Event Based Routing approach to trigger dependent modules.

Here we will describe how the router attached to a module (module.router) actually responds when it is invoked, and how modules register the routes that they will respond to. This will be described in more detail, with examples in the initialisation and routing section describing how modules work, but here we will talk about the functions provided in the lib/Router.js library that allow the modules to function.

lib/Router.js

This file exports a single function that creates a router for a specified module, this is invoked as each module is loaded, and then attached to the module in calipso.modules (e.g. calipso.modules.content.router).

This object exposes the following properties and functions:

moduleName: 'contentVersions',
modulePath: 'modules/core/contentVersions',
addRoute: [Function],
routes: [],
route: [Function]

The local storage of moduleName and modulePath are there to simplify debugging and logging, allowing the router to access these details without worrying about its parent object.

The next three are the critical ones and will be described in turn.

addRoute

This function is called to add a route to the router. This function takes the following parameters:

addRoute: function(path, fn, options, next);

path:  a string in the form 'GET /url' where the first piece is the HTTP method to respond to.
       OR
       a regex function (it matches only on GET requests).
fn:    the function in the module to call if the route matches.
options: optional additional configuration options, specifically:
    template - the name of the template to use to render the function output
    block - the name of the block in the response to put the rendered output into
    admin - is the route an administrative route (user must have isAdmin = true)

Example 1: Specific URL - /template

To create a route that responds to the specific URL of http://server/template.

module.router.addRoute('GET /template', templatePage, {
  template: 'templateShow',
  block: 'content'
}, this.parallel());

Note: The use of this.parallel() as the next function is due to the fact that most routes are defined within the module initialisation function, and are controlled by step.

Lets walk through each of these parameters in sequence.

'GET /template'

This is the description of the route that will be matched based on the incoming request. The matching approach is lifted exactly from Express, so if you are familiar with how url matching in Express works you will be familiar with out it works in Calipso.

In this example it is a string, not a regex function. The format of this string takes the following format:

'<HTTP METHOD> <URL>'

Where:

<HTTP METHOD> = GET, PUT, POST, DEL
<URL> = relative url, can include selectors prefixed by a : - e.g. /content/:id that will be captured as moduleParams

For example:

'GET /template'
'GET /content/:id'
'POST /content'
'GET /content/show/:id/versions/diff/:a/:b' 

The final of these will result in the actual url being matched, with the params being pulled out into the moduleParams hashmap:

'/content/show/1234/versions/diff/1/4' => MATCH

req.moduleParams === {id:'1234',a:'1',b:'4'};

You can also specify optional parameters, e.g. 'GET /content/:id.:format?'.

Note on Query String

If you pass any parameters as query string parameters (e.g. /template?id=1) these will not be matched as part of the url, but will be extracted by the router and added to the moduleParams hashmap. If they duplicate those matched in the URL they will over-ride them (e.g. these happen last).

Note on Form Submission

Often forms are submitted as part of a POST, these are processed outside of the router (in the core Calipso library, as forms need to be processed by formidable as early in the request processing chain as possible. Once it is processed, the contents of any form are available on the request object - req.form.

Clone this wiki locally