Overview
Express 4 is a breaking change from Express 3, so. That means an existing Express 3 app will not work if you update the Express version in its dependencies.
This article covers:
- Changes in Express 4.
- An example of migrating an Express 3 app to Express 4.
- Upgrading to the Express 4 app generator.
Changes in Express 4
There are several significant changes in Express 4:
- Changes to Express core and middleware system. The dependencies on Connect and built-in middleware were removed, so you must add middleware yourself.
- Changes to the routing system.
- Various other changes.
See also:
Changes to Express core and middleware system
Express 4 no longer depends on Connect, and removes all built-in middleware from its core, except for the express.static
function. This means that Express is now an independent routing and middleware web framework, and Express versioning and releases are not affected by middleware updates.
Without built-in middleware, you must explicitly add all the middleware that is required to run your app. Simply follow these steps:
- Install the module:
npm install --save <module-name>
- In your app, require the module:
require('module-name')
- Use the module according to its documentation:
app.use( ... )
The following table lists Express 3 middleware and their counterparts in Express 4.
Express 3 | Express 4 |
---|---|
express.bodyParser | body-parser + multer |
express.compress | compression |
express.cookieSession | cookie-session |
express.cookieParser | cookie-parser |
express.logger | morgan |
express.session | express-session |
express.favicon | serve-favicon |
express.responseTime | response-time |
express.errorHandler | errorhandler |
express.methodOverride | method-override |
express.timeout | connect-timeout |
express.vhost | vhost |
express.csrf | csurf |
express.directory | serve-index |
express.static | serve-static |
Here is the complete list of Express 4 middleware.
In most cases, you can simply replace the old version 3 middleware with its Express 4 counterpart. For details, see the module documentation in GitHub.
app.use
accepts parameters
In version 4 you can use a variable parameter to define the path where middleware functions are loaded, then read the value of the parameter from the route handler. For example:
app.use('/book/:id', function(req, res, next) { console.log('ID:', req.params.id); next(); });
The routing system
Apps now implicitly load routing middleware, so you no longer have to worry about the order in which middleware is loaded with respect to the router
middleware.
The way you define routes is unchanged, but the routing system has two new features to help organize your routes:
- A new method,
app.route()
, to create chainable route handlers for a route path. - A new class,
express.Router
, to create modular mountable route handlers.
app.route()
method
The new app.route()
method enables you to create chainable route handlers for a route path. Because the path is specified in a single location, creating modular routes is helpful, as is reducing redundancy and typos. For more information about routes, see Router()
documentation.
Here is an example of chained route handlers that are defined by using the app.route()
function.
app.route('/book') .get(function(req, res) { res.send('Get a random book'); }) .post(function(req, res) { res.send('Add a book'); }) .put(function(req, res) { res.send('Update the book'); });
express.Router
class
The other feature that helps to organize routes is a new class, express.Router
, that you can use to create modular mountable route handlers. A Router
instance is a complete middleware and routing system; for this reason it is often referred to as a “mini-app”.
The following example creates a router as a module, loads middleware in it, defines some routes, and mounts it on a path on the main app.
For example, create a router file named birds.js
in the app directory, with the following content:
var express = require('express'); var router = express.Router(); // middleware specific to this router router.use(function timeLog(req, res, next) { console.log('Time: ', Date.now()); next(); }); // define the home page route router.get('/', function(req, res) { res.send('Birds home page'); }); // define the about route router.get('/about', function(req, res) { res.send('About birds'); }); module.exports = router;
Then, load the router module in the app:
var birds = require('./birds'); ... app.use('/birds', birds);
The app will now be able to handle requests to the /birds
and /birds/about
paths, and will call the timeLog
middleware that is specific to the route.
Other changes
The following table lists other small but important changes in Express 4:
Object | Description |
---|---|
Node.js | Express 4 requires Node.js 0.10.x or later and has dropped support for Node.js 0.8.x. |
| The |
| The |
| The |
| Use |
| No longer resolves relative URLs. |
| Was an array; now an object. |
| Was a function; now an object. |
| Changed to |
| Now available as |
| Removed. |
| Removed. |
| Functionality is now limited to setting the basic cookie value. Use |
Example app migration
Here is an example of migrating an Express 3 application to Express 4. The files of interest are app.js
and package.json
.
Version 3 app
app.js
Consider an Express v.3 application with the following app.js
file:
var express = require('express'); var routes = require('./routes'); var user = require('./routes/user'); var http = require('http'); var path = require('path'); var app = express(); // all environments app.set('port', process.env.PORT || 3000); app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'pug'); app.use(express.favicon()); app.use(express.logger('dev')); app.use(express.methodOverride()); app.use(express.session({ secret: 'your secret here' })); app.use(express.bodyParser()); app.use(app.router); app.use(express.static(path.join(__dirname, 'public'))); // development only if ('development' == app.get('env')) { app.use(express.errorHandler()); } app.get('/', routes.index); app.get('/users', user.list); http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); });
package.json
The accompanying version 3 package.json
file might look something like this:
{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node app.js" }, "dependencies": { "express": "3.12.0", "pug": "*" } }
Process
Begin the migration process by installing the required middleware for the Express 4 app and updating Express and Pug to their respective latest version with the following command:
$ npm install serve-favicon morgan method-override express-session body-parser multer errorhandler express@latest pug@latest --save
Make the following changes to app.js
:
-
The built-in Express middleware functions
express.favicon
,express.logger
,express.methodOverride
,express.session
,express.bodyParser
andexpress.errorHandler
are no longer available on theexpress
object. You must install their alternatives manually and load them in the app. -
You no longer need to load the
app.router
function. It is not a valid Express 4 app object, so remove theapp.use(app.router);
code. -
Make sure that the middleware functions are loaded in the correct order - load
errorHandler
after loading the app routes.
Version 4 app
package.json
Running the above npm
command will update package.json
as follows:
{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node app.js" }, "dependencies": { "body-parser": "^1.5.2", "errorhandler": "^1.1.1", "express": "^4.8.0", "express-session": "^1.7.2", "jade": "^0.1.0", "method-override": "^2.1.2", "morgan": "^1.2.2", "multer": "^0.1.3", "serve-favicon": "^2.0.1" } }
app.js
Then, remove invalid code, load the required middleware, and make other changes as necessary. The app.js
file will look like this:
var http = require('http'); var express = require('express'); var routes = require('./routes'); var user = require('./routes/user'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var methodOverride = require('method-override'); var session = require('express-session'); var bodyParser = require('body-parser'); var multer = require('multer'); var errorHandler = require('errorhandler'); var app = express(); // all environments app.set('port', process.env.PORT || 3000); app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'pug'); app.use(favicon(__dirname + '/public/favicon.ico')); app.use(logger('dev')); app.use(methodOverride()); app.use(session({ resave: true, saveUninitialized: true, secret: 'uwotm8' })); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(multer()); app.use(express.static(path.join(__dirname, 'public'))); app.get('/', routes.index); app.get('/users', user.list); // error handling middleware should be loaded after the loading the routes if ('development' == app.get('env')) { app.use(errorHandler()); } var server = http.createServer(app); server.listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); });
Unless you need to work directly with the http
module (socket.io/SPDY/HTTPS), loading it is not required, and the app can be simply started this way:
app.listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); });
Run the app
The migration process is complete, and the app is now an Express 4 app. To confirm, start the app by using the following command:
$ node .
Load http://localhost:3000 and see the home page being rendered by Express 4.
Upgrading to the Express 4 app generator
The command-line tool to generate an Express app is still express
, but to upgrade to the new version, you must uninstall the Express 3 app generator and then install the new express-generator
.
Installing
If you already have the Express 3 app generator installed on your system, you must uninstall it:
$ npm uninstall -g express
Depending on how your file and directory privileges are configured, you might need to run this command with sudo
.
Now install the new generator:
$ npm install -g express-generator
Depending on how your file and directory privileges are configured, you might need to run this command with sudo
.
Now the express
command on your system is updated to the Express 4 generator.
Changes to the app generator
Command options and use largely remain the same, with the following exceptions:
- Removed the
--sessions
option. - Removed the
--jshtml
option. - Added the
--hogan
option to support Hogan.js.
Example
Execute the following command to create an Express 4 app:
$ express app4
If you look at the contents of the app4/app.js
file, you will notice that all the middleware functions (except express.static
) that are required for the app are loaded as independent modules, and the router
middleware is no longer explicitly loaded in the app.
You will also notice that the app.js
file is now a Node.js module, in contrast to the standalone app that was generated by the old generator.
After installing the dependencies, start the app by using the following command:
$ npm start
If you look at the npm start script in the package.json
file, you will notice that the actual command that starts the app is node ./bin/www
, which used to be node app.js
in Express 3.
Because the app.js
file that was generated by the Express 4 generator is now a Node.js module, it can no longer be started independently as an app (unless you modify the code). The module must be loaded in a Node.js file and started via the Node.js file. The Node.js file is ./bin/www
in this case.
Neither the bin
directory nor the extensionless www
file is mandatory for creating an Express app or starting the app. They are just suggestions made by the generator, so feel free to modify them to suit your needs.
To get rid of the www
directory and keep things the “Express 3 way”, delete the line that says module.exports = app;
at the end of the app.js
file, then paste the following code in its place:
app.set('port', process.env.PORT || 3000); var server = app.listen(app.get('port'), function() { debug('Express server listening on port ' + server.address().port); });
Ensure that you load the debug
module at the top of the app.js
file by using the following code:
var debug = require('debug')('app4');
Next, change "start": "node ./bin/www"
in the package.json
file to "start": "node app.js"
.
You have now moved the functionality of ./bin/www
back to app.js
. This change is not recommended, but the exercise helps you to understand how the ./bin/www
file works, and why the app.js
file no longer starts on its own.
Please login to continue.