Best way to do dynamic routing with Express.js (node.js)

Toni Lähdekorpi picture Toni Lähdekorpi · Mar 11, 2013 · Viewed 23.5k times · Source

I'm trying to create a simple CMS with express.js that dynamically creates routes. It gets a JSON from a database that looks like this:

pagesfromdb = {
    home = {
        paths = ['/','/home','/koti'],
        render = 'home.ejs',
        fi_FI = {html='<h1>Hei maailma!</h1>'},
        en_US = {html='<h1>Hello World!</h1>'}
    },
    about = {
        paths = ['/about','/tietoja'],
        render = 'general.ejs',
        fi_FI = {html='Tietoja'},
        en_US = {html='About Us'}
    }
}

and iterates over the objects creating routes like so:

Object.keys(pagesfromdb).forEach(function(key) {
    var page = pagesfromdb[key];
    app.get(page.global.paths,function(req, res){
         res.render(page.render, page[language]);
    });
});

Now everything is working fine. But the problem is, every time a user modifies the content and paths, the whole node app needs to be restarted. I didin't find any API calls to remove routes.

Is there any way to safely remove the old routes set with app.get? Should I even do that?

Is there a better way to do this kind of routing? I do like this method as it allows me to use the built in function, is fast and supports regex.

I tried removing the whole app.routes with app.routes = nul but it didn't do anything, the old routes were still in place.

One thing that did indeed remove them was

delete app._router.map.get;
app._router.map.get = [];

But does this actually remove them and is it safe to use so I don't end up hijacking huge amounts of ram if the router keeps getting repopulated?

Answer

Max picture Max · Mar 12, 2013

As @supermova said in the comments, it is possible to update Express on-the-fly. Another architecture to consider is the one similar to classic CMSs (like Wordpress, for example). In other CMSs, all requests go to the same 'callback' and on every request you look up in the database what page to serve for that URL.

app.get('/*', function (req, res) {
   db.findPage({ slug: req.url}, function (err, pageData) {
       res.render('page-template', {
           pageContent: pageData.content,
           pageTitle: pageData.title
       });
   });
});

There is a significant speed decrease as a result of this method, but in the end I think it is more sane. If speed is a huge issue you can set up a caching system (like Varnish) but there will be headaches with the approach of modifying Express routes on-the-fly. For example, what if you have to scale to two web servers? How do you keep them in sync if server A gets the 'create page' request and so it knows to update its routes, but what about server B? With every request going to the database you will be able to scale horizontally better.