DEV Community

Cover image for An Introductory Guide to Migrating Express.js V4 to V5
Pieces ๐ŸŒŸ
Pieces ๐ŸŒŸ

Posted on • Updated on • Originally published at code.pieces.app

An Introductory Guide to Migrating Express.js V4 to V5

A subway tunnel.

Node.js is a quick JavaScript runtime environment used for creating server-side apps. Express.js is needed to handle file serving, request handling, and HTTP method handling. According to its documentation, Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.

In this tutorial, we'll explore the newly released Express.js V5 and how to upgrade from Express.js V4 to V5. We'll also look at the enhancements and new features provided by Express.js V5, as well as explore how it can be used to build a web application.

The recently released Express.js V5 contains a number of enhancements and new features aimed at boosting the functionality of the framework. The migration from V4 to V5 might be a little disconcerting, though, because of possible problems or deprecation of features within this update.

Overview of Express.js

Express.js as a Node.js backend framework is efficient for building restful server-side applications. Express.js apps process client requests using particular HTTP request methods and route paths. They also carry out route handler callbacks that have been set up for the routes.

Express has a well-structured approach to middleware functions that can easily be incorporated into the request-response processing cycles. The structure gives each middleware function the needed access to other middleware functions, forming a chain of addition processing on the incoming request and the outgoing response. This provides the developers with easy access and termination of request-response cycles within the middleware functions.

Why Migrate from Express.js V4 to V5?

At the core of the new features and improvements in Express.js V5 is the increased efficiency of the framework. This improves the general performance of the server-side applications built with it. Amongst the improvements is the handling of rejected promises. Previously, we explicitly implemented error handlers for rejected promises or errors. Now, we can simply send the errors to an error handling middleware to properly process them as well.

Let's explore the changes even further, but please note that Express.js V5 is still in its beta stage.

Rejected Promise and Error Handling

In Express.js V4, when an error or rejection in a request handler is not explicitly handled or passed down to an error-handling middleware, it could potentially cause the app to crash. However, with Express.js V5, the application doesnโ€™t crash; instead, a 500 response containing either the error or the rejected value is returned. Better yet, we can handle the event by passing it down to an error-handling middleware.

app.get("/throw", async () => {
 return await Promise.resolve().then(() => {
 throw new Error("Pieces: error");
  });
});

app.get("/reject", () => {
 return Promise.reject("Pieces: rejected");
});
Enter fullscreen mode Exit fullscreen mode

Save this code

The above snippet would surely crash the entire application in Express.js V4, but thanks to V5 updates, it wonโ€™t.

Return of app.router Object

The app.router reference object to an Express appโ€™s built-in router instance, which was removed in Express.js V4, has been brought back in V5. Now, we can define middleware and routes on the app.router object:

const express = require("express");
const app = express();
const router = app.router;

router.post("/create", (req, res) => {
 // do something...
  res.status(status).send("Created from Pieces!");
});
Enter fullscreen mode Exit fullscreen mode

Save this code

Change of Syntax for Route Path Matching

Express.js V5 came with new parameter modifiers to the route path. Route paths, which define endpoints as strings, string patterns, or regular expressions, are mostly utilized in app and router objects for incoming requests. These changes include:

  • The use of the ?, *, and + characters, which should be added as suffixes to route parameters.
  • The use of ? to specify optional parameters.
  • The use of * to match zero or more parameters.
  • The use of + for one or more parameters.
  • When using regular expressions in matching groups:
  • /(\\d+) replaced /\\d+
  • (*) wonโ€™t be valid any longer, and must be written as (.*).
  • The use of req.params in a named matching group like /:foo(.*) can only be captured as req.params.foo, and is not available as req.params[0].
app.get("/inventory/:ids*/pieces", (req, res) => {
  res.status(status).send("Check the warehouse inventory!");
});
Enter fullscreen mode Exit fullscreen mode

Save this code

The above snippet shows a route path that will match /inventory/pieces, /inventory/1/pieces, /inventory/1/2/pieces, and so on when substituted.

app.get("/inventory/:ids+/pieces", (req, res) => {
  res.status(status).send("Get the warehouse inventory with id!");
});
Enter fullscreen mode Exit fullscreen mode

Save this code

The above snippet shows a route path that will match /inventory/1/pieces, /inventory/1/2/pieces, and so on when substituted, but not /inventory/pieces.

app.get("/inventory/:id?/pieces", (req, res) => {
  res.status(status).send("Check only the warehouse inventory!");
});
Enter fullscreen mode Exit fullscreen mode

Save this code

The above snippet shows a route path that will match /inventory/pieces, /inventory/1/pieces, and so on when substituted, but not /inventory/1/2/pieces.

As mentioned above, all matching group expressions have to be RegExp. In Express.js V4, the use of (*) in route path was valid, but will fail in Express.js V5. The valid RegExp equivalent is (.*).

app.get("/inventory/:id(.*)", (req, res) => {
  res.status(status).send(req.params);
});
Enter fullscreen mode Exit fullscreen mode

Save this code

The above snippet will return {"id":"1"} as a response in Express.js V5, unlike (*), which will return {"0":"1","id":"1"} as a response in Express.js V4.

Asynchronous Behavior by res.render

The res.render in Express.js V5 now supports asynchronous callback as its parameter. This improvement helps avoid bugs caused by view engines that are synchronous in implementation; the callback function handles any rendering error that may occur when trying to send the rendered HTML as a response to the client.

Changes to the req.query Object

The nature of the req.query property has been changed to a getter, unlike its writable nature in Express.js V4. The default query parser has been changed from extended to simple. This update also comes with the equivalent setter to change the default query parser if need be.

const express = require("express");
const app = express();
console.log(app.get("query parser"));
app.set("query parser", "extended");
Enter fullscreen mode Exit fullscreen mode

Save this code

The Use of req.host to Manage Port

The req.host property now manages and returns the host value from the Host HTTP header. For example, if the server-side application is running on http://localhost:8080, then the code below will return localhost:3000 on Express.js V5:

app.get("/heath-check", (req, res) => {
  res.status(status).send(`host: ${req.host}`);
});
Enter fullscreen mode Exit fullscreen mode

Save this code

Additional Breaking Changes in Express.js V5 from V4

Letโ€™s enumerate some potential breaking changes introduced in V5:

  • The req.acceptsCharset(), req.acceptsEncoding(), and req.acceptsLanguage() functions have been pluralized to req.acceptsCharsets(), req.acceptsEncodings(), and req.acceptsLanguages() in Express.js V5.
  • The app.del() function for registering HTTP DELETE routes has been renamed to app.delete().

The following function signatures have been changed as shown below:

  • res.json(obj, status) to res.status(status).json(obj)
  • res.send(body, status) to res.status(status).send(obj)
  • res.jsonp(obj, status) to res.status(status).jsonp(obj)
  • res.send(status) (where status is a number) to res.sendStatus(statusCode)
  • res.sendfile() to res.sendFile()
  • The deprecated function signature, app.param(fn), is no longer supported in Express.js V5

Migrating an Existing Express.js V4 Application to V5

Luckily, migrating an existing server-side application to Express.js V5 wonโ€™t involve a lot of heavy lifting. The first approach would be to upgrade from V4 to V5 of Express.js by running the command below:

npm install "express@>=5.0.0-beta.1" --save
Enter fullscreen mode Exit fullscreen mode

First, run the npm outdated command to see any packages that need to be updated. Next, re-run any existing test suites on the project, or rebuild the entire project to see all breaking changes. Follow the tutorial to fix any issues that occur.

Conclusion

In this article, we explored the exciting new features and improvements in Express.js V5, including the addition of route parameter modifier characters, and improved RegExp parsing in route paths. Express.js V5 has restored critical attributes and values that were absent from Express.js V4, such as app.router and the port in req.host. Furthermore, synchronous view rendering bugs have been resolved. Likewise, V5 handles rejected promise handling in middleware and handlers automatically. For more information about Express.js V5, check out the documentation.

Top comments (0)