Migrating Express.js 3.x to 4.x: Middleware, Route and Other Changes

Migrating Express.js 3.x to 4.x: Middleware, Route and Other Changes

Express.js 4 is the latest (as of May 2014) version of the most popular mature and robust Node.js framework for web apps, services and APIs. There are some breaking changes going from 3.x to 4.x, so here’s a brief migration guide:

Replacing Unbundled Middleware in Express.js 4

Let’s start with the biggest change that will break most of your Express.js 3.x projects. This is also the most discussed news (and long awaited?) on the Internet. Yes, it’s unbundled middleware.

Personally, I’m not sure whether it’s good or bad, because I kind of liked not having to declare extra dependencies. However, I can see the arguments for unbundling as well, including things like keeping the Express.js module small, upgrading middleware packages independently, etc.

So what is unbundled middleware? Remember the magic middleware that we used by just typing app.use(express.middlwarename())? Well, they were coming from the Connect library and now they are gone from Express.js. It was customary to write, for example app.use(express.cookieParser()) in Express.js 3.x. Those modules are very important and essential for pretty much any web application. They were part of the Connect library, but Express.js 4.x doesn’t have Connect as a dependency. This means that if we want to use it (and we sure do!), we’ll need to explicitly include middleware like this:

$ npm install body-parse@1.0.2 --save

And then in the Express.js main configuration file (e.g., app.js), use the included module like this:

var bodyParser = require('body-parse')
... //other dependencies
app.use(bodyParser())
... //some other Express.js app configuration

Kapish?

Here’s the list of the unbundled middleware that developers will have to replace: all except static. That’s right, static was left out. In the list below, on the left the Express.js 3.x middleware names, and on the right side are their NPM module counterparts for the Express.js 4.x usage:

  • express.bodyParser: body-parser (GitHub)
  • express.compress: compression (GitHub)
  • express.timeout: connect-timeout (GitHub)
  • express.cookieParser: cookie-parser (GitHub)
  • express.cookieSession: cookie-session (GitHub)
  • express.csrf: csurf (GitHub)
  • express.error-handler: errorhandler (GitHub)
  • express.session: express-session (GitHub)
  • express.method-override: method-override (GitHub)
  • express.logger: morgan (GitHub)
  • express.response-time: response-time (GitHub)
  • express.favicon: serve-favicon (GitHub)
  • express.directory: serve-index (GitHub)
  • express.static: serve-static (GitHub)
  • express.vhost: vhost (GitHub)

To make matters a bit more complicated, Express.js/Connect team is dropping support for the following modules and recommending that you use alternatives:

Many of these unbundled Express.js/Connect modules are looking for maintainers; make a dent in the Node.js universe!

Removing Deprecated Methods from Express.js 4 Apps

app.configure()

I don’t think most people ever used it. app.configure() was a sugar-coating which was nice but a non-essential piece mostly meant for setting up environments. If you have it, just replace app.configure('name', function(){...}) with if (process.env.NODE_ENV === 'name') {...}. For example, this old Express.js 3 production configuration:

app.configure('production', function() {
  app.set('port', 80)
})

In Express.js 4.x, becomes:

if (process.env.NODE_ENV === 'production) {
  app.set('port', 80)
})

PS: If you look into Express.js 3.x code on GitHub, that’s exactly what app.configure() did. ;-)

app.router

One of the good changes is that the need to write app.router has been eliminated! So now, basically the order of middleware and routes is the only thing that counts, but before developers were able to augment the order of execution by placing app.router somewhere in the middle.

If you had any middleware that is supposed to be after the routes (but in the old wasn’t due to deprecated app.router) move it after the route, just in the order you want them.

For example before, there is error handling middleware which is executed after routes in the Express.js 3.x:

app.use(express.cookieParser())
app.use(app.router)
app.use(express.errorHandler())
app.get('/', routes.index)
app.post('/signup', routes.signup)

Migrates into this code in Express.js 4.x:

var cookieParse = require('cookie-parser')
var errorHandler = require('errorhandler')
...
app.use(cookieParser())
app.get('/', routes.index)
app.post('/signup', routes.signup)
app.use(errorHandler())

In other words, app.use() and routes with verbs such as app.get(), app.post(), app.put() and app.del() became equal counterparts.

res.on(‘header’)

res.on('header') was removed from Connect 3.

res.charset

In Express.js 4.x, use res.type() or res.set('content-type') instead of res.charset in Express.js 3.x.

res.headerSent

Use res.headersSent instead.

req.accepted()

Use req.accepts() instead.

req.accepted in Express.js 4.x is powered by the module accepts (GitHub), which was “extracted from Koa.js for general use” as the documentation says.

Other Express.js 4 Changes

app.use()

Amazingly, app.use() now accepts URL parameters. This is another step towards making app.use() and verb route methods equal and less confusing. The parameter is in the req.params object.

For example, if we need to get ID from the URL, in Express.js 4.x middleware, we can write:

app.use('/posts/:slug', function(req, res, next) {
  req.db.findPostBySlug(req.params.slug, function(post){
  ...
  })
})

res.location()

It’s not resolving relative URL.

app.route

Look below at the section called “Express.js 4 Route Instance and Chaining It”.

json spaces

json spaces is off by default in development

req.params

req.params is an object, not an array.

res.locals

res.locals is an object now.

req.is

req.is in Express.js 4.x was replaced by the module type-is (GitHub), which was also “extracted from [Koa.js](http://koajs.com for general use” as the documentation says.

Express.js Command-Line Generator

For the command-line generator use

$ sudo npm install -g express-generator

Instead of old plain $ sudo npm install -g express.

Express.js 4 Route Instance and Chaining It

The app.route() method gives us the new Express.js 4 Route instance, but before we explore it, let’s take a look at the router itself.

The Router class has been supercharged in Express.js 4.x. Before the app instance used router, but now we can create many route instances and use the for specific paths by attaching particular middleware and other logic. This can be used to re-organize code. This of Router as a mini Express.js application!

Here’s a basic example on how developers can use Router in Express.js 4.x. Let’s say we have reviews for two categories: books and games. The reviews logic is similar to and packaged as a router:

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

router.use(function(req, res, next) {
  //process each request
});

router.get('/', function(req, res, next) {
  // get the home page for that entity 
  next();
});

router.get('/reviews', function(req, res, next) {
  // get the reviews for that entity
  next();
});

app.use('/books', router);
app.use('/games', router);

app.listen(3000);

app.route() or router.route() returns us the new Express.js 4.x route instance which we can chain like this:

router.route('/post/:slug')
  .all(function(req, res, next) {
    // runs each time
    // we can fetch the post by id from the database
  })
  .get(function(req, res, next) {
    //render post
  })
  .put(function(req, res, next) {
    //update post
  })
  .post(function(req, res, next) {
    //create new comment 
  })
  .del(function(req, res, next) {
    //remove post
  })

While in Express.js we would have to type the same path again and again (asking for a typo mistake):


router.all('/post/:slug', function(req, res, next) {
  // runs each time
  // we can fetch the post by ID from the database
})
router.get('/post/:slug', function(req, res, next) {
  //render post
})
router.put('/post/:slug', function(req, res, next) {
  //update post
})
router.post('/post/:slug', function(req, res, next) {
  //create new comment 
})
router.delete('/post/:slug', function(req, res, next) {
  //remove post
})

The same Route instance can also have its own middleware, param, and HTTP verb methods (as illustrated above).

Further Express.js 4 Migration Reading Links

So overall, the Express.js 4.x changes are not very dramatic, and the migration can go relatively painless. But just before you hit $ git checkout -b express4 to create a new branch for your migration from 3.x, think if you really need to do it! I know many successful production applications that haven’t updated their main framework versions. At Storify, we used to run Express.js 2.x when 3.x was available and it was a big deal. Another example from the Ruby world, I know many apps and developers who still work with Ruby on Rails 2.x when there is Ruby on Rails 4.x.

In case you decide to go with Express.js 4, don’t rely just on this brief overview. Take a look at these additional resources to help make a transition from Express.js 3.x to 4.x easier:

Author: Azat

Techies, entrepreneur, 20+ years in tech/IT/software/web development expert: NodeJS, JavaScript, MongoDB, Ruby on Rails, PHP, SQL, HTML, CSS. 500 Startups (batch Fall 2011) alumnus. http://azat.co http://github.com/azat-co

8 thoughts on “Migrating Express.js 3.x to 4.x: Middleware, Route and Other Changes”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.