An Introductory Guide to Migrating Express.js V4 to V5
Published: 2022-10-31 18:18:29

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/migratingexpress_js_780ed6f854ee1bd1dd3aacde4308b6e3.jpg" alt="A subway tunnel."/></figure>

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](https://expressjs.com/) 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");
});
```

[Save this code](https://user-d6b93f60-4441-4576-aac8-a041d598ff4c-fhcmbheklq-uc.a.run.app/?p=44c845ab2f)

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!");
});
```

[Save this code](https://user-d6b93f60-4441-4576-aac8-a041d598ff4c-fhcmbheklq-uc.a.run.app/?p=c75b4a885f)

### 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!");
});
```

[Save this code](https://user-d6b93f60-4441-4576-aac8-a041d598ff4c-fhcmbheklq-uc.a.run.app/?p=41bc469248)

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!");
});
```

[Save this code](https://user-d6b93f60-4441-4576-aac8-a041d598ff4c-fhcmbheklq-uc.a.run.app/?p=6bf64fb9c7)

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!");
});
```

[Save this code](https://user-d6b93f60-4441-4576-aac8-a041d598ff4c-fhcmbheklq-uc.a.run.app/?p=39514fbbc4)

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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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);
});
```

[Save this code](https://user-d6b93f60-4441-4576-aac8-a041d598ff4c-fhcmbheklq-uc.a.run.app/?p=c18e4db824)

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");
```

[Save this code](https://user-d6b93f60-4441-4576-aac8-a041d598ff4c-fhcmbheklq-uc.a.run.app/?p=007c4293ac)

### 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}`);
});
```

[Save this code](https://user-d6b93f60-4441-4576-aac8-a041d598ff4c-fhcmbheklq-uc.a.run.app/?p=064344bd44)

### 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
```

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](https://expressjs.com/en/guide/migrating-5.html).