#NodeJS / #ExpressJS: Adding routes dynamically at runtime

Written on February 02, 2015

When running a ExpressJS based API or Website, you may want to add new routes without restarting your ExpressJS host.

Actually, adding routes to ExpressJS at runtime is pretty simple.

First, lets create some "design time" routes for an API endpoint as well as some static content to be served by our ExpressJS application:

var express = require('express');
var app = express();

// development time route
app.get('/api/hello', function(request,response) {
    return response.status(200).send({"hello":"world"})
});

// static file handling
app.use(express.static(__dirname + '/client/app'));


app.listen(3000);

A call to http://localhost:3000/api/hello will return this:

{"hello":"world"}

And the call to http://localhost:3000 will render us some HTML:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Hello World!</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>

Nothing special here, move along :)

Now, lets assume we're dropping a new ExpressJS controller into our ./controllers folder at runtime:

module.exports= {
    init : init
};

function init(app){
    app.get('/api/myruntimeroute', function(req,res) {
        res.send({"runtime" : "route"});
    })
}

When calling it's route http://localhost:3000/api/myruntimeroute we'll get a 404. Sad panda.

Now lets drop this piece of code into our app.js before the app.listen(3000) line (this needs to be added before the host is started, of course):

// hook to initialize the dynamic route at runtime
app.post('/api/dynamic', function(req,res) {
    var dynamicController = require('./controllers/RuntimeController');
    dynamicController.init(app);
    res.status(200).send();
});

When sending a POST (curl -X POST http://localhost:3000/api/dynamic) to that endpoint, our controller dropped in at runtime, now gets initalizied and can register it's routes.

Calling http://localhost:3000/api/myruntimeroute now GETs us some fancy JSON:

{"runtime" : "route"}

Looking back to the hookup code, you can see that the name of the controller is already known which of course is just for the sake of simplicity of this sample.

In a real world implementation you might have some other hook up like a user action in your administration which looks for new controllers in a specific folder. Or you might monitor a specfic folder for new controller files. You get the point.

Another approach for dynamic runtime routing could be to have catch some/all route definition which hooks in when all other routes fail.

A small example:

app.get('/api/:dynamicroute', function(req,res) {
    res.send({"param" : req.params.dynamicroute});
});

In this snippet, the part behind the /api/ path is dynamic which means you can have some logic which distributes the requests based on decisions made at runtime.

You can find the source code for this sample in this GitHub repository.