Defining routes: namespace routing in Express.js and Node.js

Defining routes: namespace routing in Express.js and Node.js

Hi, in this article I would like to describe one of the ways of doing the routes which we can use in our Express.js development process. Yes, it will be a name spaced routing way. I think it is the one of my favourite ways of doing this, but at the beginning I would like to add a few words about the routing, put a short review and then show how it works. I think it will helps someone who is just curious and don’t want to go into details.

What are routes?

Routes are url’s, which describe the way for making requests to the application.

address

The simplest route can looks like the following code:

app.get('/', function(req, res) {
     res.send('Simple route has been called.');
});

The first parameter is your url path and second one is a callback which do the action, but of course you can use more advanced way and implement the regular expression:

app.get('/blog/post/:id/:comment?', function(req, res){
     var id = req.params.id,
         comment = req.params.comment;
});

In the very simple apps you can use something like above to define your url’s / routes and simply put everything to app.js or server.js file. However, this flow is not recommended for largest projects, I think I don’t have to explain the reason. Express.js is very flexible and allows you to create own ways of making a requests to the application, is also happy when you want to organise yours own routes.

The most common ways of doing this:

a) node modules

b) name space routing

c) resource routing

I will describe the second one and try to show you an example of how to use it in the regular project.

Namespace routing

Simple application structure for an article example:

express-node-namespace-routing-0

The most important files:

a) app.js

var express = require('express')
    , http = require('http')
    , path = require('path')
    , namespace = require('express-namespace');

var app = express();

app.configure(function () {
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.favicon());
    app.use(express.logger('dev'));
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function () {
    app.use(express.errorHandler());
});

// router
require('./application/router')(app);

// server
http.createServer(app).listen(app.get('port'), function () {
    console.log("Express server listening on port " + app.get('port'));
});

module.exports = app;

The app.js file is a standard bootstrap file but it calls the router file which contains defined namespace routing. The router code look like the following lines:

b) router.js

module.exports = function (app) {
    /* You can do this automatically */
    var main = require('./module/main/controller');
    var user = require('./module/user/controller');

    /* main */
    app.namespace('/', function () {
        app.get('/', main.index);
        app.get('contact', main.contact);
        app.get('about', main.about);
    });

    /* user */
    app.namespace('/user', function () {
        app.get('login', user.login);
        app.get('logout', user.logout);

        // an example of namespace in namespace
        app.namespace('/settings', function () {
            app.get('/', user.settings);
            app.get('profile', user.profile);
        });

        /* REST CRUD */
        //read
        app.get('/:id?', user.read); // if is not set, go to user profile
        //create
        app.post('/', user.add);
        //update
        app.put('/', user.update);
        //remove
        app.delete('/', user.destroy);
    });
}

As you can see it’s not very complicated. The first two lines attach the controllers files (you can do this in different way, its only an example flow). The most important part here is the name space module, which was defined and installed from here:

{
    "name": "devjs-express-nampespace-route",
    "version": "0.0.1",
    "private": true,
    "scripts": {
        "start": "node app",
        "debug": "node --debug app"
    },
    "dependencies": {
        "express": "3.4.0",
        "jade": "*",
        "express-namespace": "*"
    }
}

It’s called ”express-namespace”, this module provides namespace capabilities to express. As you can see you can build own namespaces in parent namespaces, if your code will grow to bigger sizes, you can separate them using separate files etc.

The main path (main namespace part) looks like the following code:

app.namespace('/', function () {
    app.get('/', main.index);
});
express-node-namespace-routing-1

The contact path looks like the following code:

app.namespace('/', function () {
    app.get('contact', main.index);
});
express-node-namespace-routing-2

The user (a new namespace) path looks like the following code:

app.namespace('/user', function () {
    app.get('/:id?', user.read);
});
express-node-namespace-routing-3

It redirects user to his own profile because of empty id value, the action for this is defined in user action controller:

exports.read = function (req, res) {
    var id = req.params.id;

    if (!id) {
        // get user to his profile page
        return exports.profile(req, res);
    }

    res.send("read user profile with id: " + id);
};

The specific user path looks like the following code:

express-node-namespace-routing-4

The next code shows how you can use the namespace routes in the namespace modules, it means that the settings namespace is a child of user namespace:

app.namespace('/settings', function () {
    app.get('/', user.settings);
    app.get('profile', user.profile);
});

express-node-namespace-routing-5

express-node-namespace-routing-6
Conclusion

The name space module allows you to organise your code and keep it clean. Please remember that the order of defining routes if also important, so app will get the first route which match to actual requested path. For example if we change the order in the following code:

     //read
     app.get('/:id?', user.read); // if is not set, go to user profile

     // an example of namespace in namespace
     app.namespace('/settings', function () {
         app.get('/', user.settings);
         app.get('profile', user.profile);
     });

In this case user will be not able to see the main page of settings because app will get the actual path as the user id and shows something like that:

express-node-namespace-routing-7

Keep that in mind and have a fun. See you soon.

Comments:

Leave a Reply

Please fill all required fields


Drag circle to the rectangle on the right!

Send