Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 467
Toni Lähdekorpi Avatar asked Mar 11 '13 17:03

Toni Lähdekorpi


People also ask

How the dynamic routing is working in ExpressJS?

ExpressJS Online Training We can now define routes, but those are static or fixed. To use the dynamic routes, we SHOULD provide different types of routes. Using dynamic routes allows us to pass parameters and process based on them. var express = require('express'); var app = express(); app.

What is routing and how routing works in Express JS?

Routing refers to how an application's endpoints (URIs) respond to client requests. For an introduction to routing, see Basic routing. You define routing using methods of the Express app object that correspond to HTTP methods; for example, app. get() to handle GET requests and app.

How router works in Express JS?

Router() Function. The express. Router() function is used to create a new router object. This function is used when you want to create a new router object in your program to handle requests.

How does Express handle routing?

A route method is derived from one of the HTTP methods, and is attached to an instance of the express class. The following code is an example of routes that are defined for the GET and the POST methods to the root of the app. Express supports methods that correspond to all HTTP request methods: get , post , and so on.


2 Answers

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.

like image 183
Max Avatar answered Sep 25 '22 08:09

Max


I would be very careful trying to create or destroy routes at runtime. Although you can change the data structures yourself, I do not believe these are documented as API's, so you risk this breaking if/when you upgrade Express.

This could also serve as a memory constraint if you create a new route for each database object because the set of pages can grow to who knows how big.

Look at it like this... you don't want new routes; you want to add URL's to existing routes. If you are adding a route, that means you want some URL to map to some distinct function. But you are mapping each URL to the same function. In essence, you are only adding routes by side effect. What you care about is that some dynamic set of URL's map to a specific function.

Can you instead use a wildcard to map the URL pattern to a specific function, like

app.get('/pages/*', function(req, res) {
    var page = pagesfromdb[key];
    if (page != null) {
        res.render(page.render, page.language)
    }
    else {
        res.send(404);
    }
});

And manage the pagesfromdb mapping outside of the express layer. You can use direct database access, cache + database access or a timer-based refresher, whatever performs best for you.

like image 45
Brandon Avatar answered Sep 24 '22 08:09

Brandon