Sunday, December 13, 2015

More Node.JS Module Patterns

The post on Node.JS module patterns and the slideshow from the talk I did at OttawaJS keep getting a lot of mentions. Those are really simple examples, but in practice most modules have a bit more substance to them.

There are a couple of patterns that I've seen used in Express.JS apps a lot.  One simply exports a bunch of functions that are used as route handlers. Another passes an object to the module, and the module attaches things to it.  And the last one exports an Express router object that the main app can use to define more specific routes on a base URL.

Let's look at these with some simple examples.

Exporting route handler functions

This is a fairly common pattern where the module simply exports a number of functions. In this case they're route handler functions that an Express app can use to handle the various routes it declares.

users.js

exports.getUser = function (req, res, next) {
  res.send('respond with a user');
};

exports.updateUser = function (req, res, next) {
  res.send('update user and respond');
};

app.js

var users = require('users.js');

app.get('/user/:userid', users.getUser);
app.put('/user/:userid', users.updateUser);

Passing in and enhancing an object

This pattern has been used in some Express example apps and shows how you can pass variables into a module, either to use them in the module or to "enhance" an object by attaching things onto it. Of course you have to know what you're doing and not have two different modules that try to do the same thing.

users.js
module.exports = function (app) {
  app.get('/user/:userid', function (req, res, next) {
    res.send('respond with a user');
  });
};

app.js

var users = require('users.js')(app);

Express router modules

The most recent version of express-generator creates a sample app using this pattern. Route modules are created under the routes/ directory, and they require an instance of the Express router. They add their routes to the router instance, and set module.exports as the router object. The main app.js file then attaches these router objects via app.use('/path', router) as you can see below. It's a nice clean way to organize route modules in Express.

users.js

var express = require('express');
var router = express.Router();

router.get('/:userid', function (req, res, next) {
  res.send('respond with a user');
});

module.exports = router;

app.js
var express = require('express');
var users = require('users.js');
var app = express();
app.use('/users', users);

Translate