Deftly🦅 Handle exceptions in Node/Express Application
Tags: webdev, express, beginners, tutorial
Published: 2023-03-31 09:39:27

<small>Welcome to <b>part 4</b>. Follow along this series to build a 3-tier Login System implementing core features required of an effective and usable authentication system.</small>

_**Summary:** In this tutorial, you will learn to create user-defined exceptions and handle these exceptions (or other unexpected events) as they occur through proper error handling in express_.

> _**Note 🔔**_:  
> _If you would like to jump ahead to the finally built authentication system, the complete Git Repo can be found on [Github](https://github.com/hane-smitter/MERN_login_system)✩._

With how Javascript engine works, when a runtime error occurs, execution will stop and an error is generated. In technical parlance, _a runtime error causes new `Error` object to be **created and thrown**_. In such an event, the rest of code is not executed.

Well, that is how Javascripts handles itself when you _write bad code_. Likewise, the application you are building needs to handle itself when it receives _bad input_. Or when other unexpected events occur, including a runtime error.

For example, division by zero is not an error in Javascript. But logic in your application requires that it should be. The `throw` keyword allows you to stop javascript execution whilst generating a custom defined exception. As you generate exception, you should handle it and communicate back to the user with succinct information about what went wrong.

<details>
  <summary><b>Table of Contents</b></summary>
  <ol>
    <li>
      <a href="#what-we-will-do">What we will do</a>
      <ol>
        <li><a href="#1-create-custom-error-constructors">Create custom error constructors</a>
        <li><a href="#2-create-errorexception-handlers">Create error/exception handlers</a>
        <li><a href="#3-configure-error-handlers-in-express-application">Configure error handlers in express application</a>
        <li><a href="#4-error-handling-in-action">Error Handling in action</a>
      </ol>
    </li>
    <li><a href="#final-thoughts">Final thoughts</a></li>

  </ol>
</details>

<p id="what-we-will-do">Outline of <b>what we will do</b>:</p>

1. Create custom error constructors.
1. Create error/exception handlers.
1. Configure express application to use custom error handlers.
1. Error Handling in action.

In an error flow control, we will `throw` using a _custom error constructor_, to generate a **user-defined exception**. The generated exception will be processed in _error handler_.

### Directory structure

```diff
📂server/
└── 📂src/
    ├── 📄index.js
    └── 📂config/
+       ├── 📂errors/
+       │   ├── 📄AuthorizationError.js
+       │   └── 📄CustomError.js
+       └── 📂exceptionHandlers/
+           └── 📄handler.js
```

This is the structure in regard to the `src` directory that contains our code. We will update these files with code to provide the logic we want to achieve. You can always double check to create these files in their correct locations.

## 1. Create custom error constructors

Certainly you may be familiar with the in-built Error constructor, _i.e `new Error()`_, which actually creates an Error object.

Let's create custom error constructor which is a superset of the in-built `Error`, by which we will be able to add more properties to the created Error Object we will need later.

**First**, open the file: **`CustomError.js`**. According to the directory structure for this tutorial(<i><a href="#directory-structure">refer above</a></i>), it should be at the path: `server/src/config/errors/`. Create the constituent directories if you do not have.<br />
Inside the opened file, paste in the following code:

```javascript
class CustomError extends Error {
	/**
	 * Custom Error Constructor
	 * @param {any} [message] - Optional error payload
	 * @param {number} [statusCode] - Optional error http status code
	 * @param {string} [feedback=""] - Optional feedback message you want to provide
	 */
	constructor(message, statusCode, feedback = "") {
		super(message);
		this.name = "CustomError";
		this.status = statusCode;
		this.cause = message;
		this.feedback = String(feedback);
	}
}

module.exports = CustomError;
```

The snippet above simply creates a class that extends base `Error` class that is in-built to javascript. We define a constructor that passes `message` as first argument to the base class(_By calling `super(message)`_), and adds additional properties to the result _Error Object_ when the class is instantiated.

To cause a _user-defined exception_ in our application, we will `throw CustomError()`. Arguments can be passed to define properties on created _Error object_.

**Second**, open/create the file: **`AuthorizationError.js`**. Expected to be at the path: `server/src/config/errors/`(<i><a href="#directory-structure">refer above</a></i>).<br />
Paste the following code in the file:

```javascript
const CustomError = require("./CustomError");

class AuthorizationError extends CustomError {
	/**
	 * Authorization Error Constructor
	 * @param {any} [message] - Error payload
	 * @param {number} [statusCode] - Status code. Defaults to `401`
	 * @param {string} [feedback=""] - Feedback message
	 * @param {object} [authParams] - Authorization Parameters to set in `WWW-Authenticate` header
	 */
	constructor(message, statusCode, feedback, authParams) {
		super(message, statusCode || 401, feedback); // Call parent constructor with args
		this.authorizationError = true;
		this.authParams = authParams || {};
		this.authHeaders = {
			"WWW-Authenticate": `Bearer ${this.#stringifyAuthParams()}`,
		};
	}

	// Private Method to convert object `key: value` to string `key=value`
	#stringifyAuthParams() {
		let str = "";

		let { realm, ...others } = this.authParams;

		realm = realm ? realm : "apps";

		str = `realm=${realm}`;

		const otherParams = Object.keys(others);
		if (otherParams.length < 1) return str;

		otherParams.forEach((authParam, index, array) => {
			// Delete other `realm(s)` if exists
			if (authParam.toLowerCase() === "realm") {
				delete others[authParam];
			}

			let comma = ",";
			// If is last Item then no comma
			if (array.length - 1 === index) comma = "";

			str = str + ` ${authParam}=${this.authParams[authParam]}${comma}`;
		});

		return str;
	}
}

module.exports = AuthorizationError;
```

`AuthorizationError` is an error intended to be generated due to _insufficient authentication_.<br />
It is extends the `CustomError` class adding extra properties as well. **Majorly**, the constructor for this error class has a `statusCode` that defaults to `401` which is passed to base class(`CustomError`) when calling `super()`.<br />
Also, we have defined `#stringifyAuthParams()` private method to convert `authParams` object parameter to a list of comma separated strings of format `key=value`. The formatted string is used to generate value for the `authheaders` property.

> New to private methods in javascript classes? Read more [here](https://dev.to/smitterhane/private-class-fields-in-javascript-es2022-3b8).

Error object created using this class will be processed by error handler to produce a **401 - Unauthorized** Error response that observes the web specifications, which require a _response due to failed authentication include a `WWW-Authenticate` header_. Learn more [here](https://www.rfc-editor.org/rfc/rfc2617#page-3).

## 2. Create error/exception handlers

Here we will create handlers for unexpected events that occur in our application. These handlers are important to prevent a running program from shutting down unceremoniously to its users. Furthermore they provide concise information to the user about what went wrong.<br />
We will create **two** error handlers:

1. 404 case handler _i.e handler called when http request on a path that does not exist hits our server._
2. General exception handler _i.e handler called when exceptions are generated from anywhere in our application_.

Open the file: **`handler.js`**. According to the directory structure for this tutorial(<i><a href="#directory-structure">refer above</a></i>), it should be at the path: `server/src/config/exceptionHandlers/`. Create the constituent directories if you do not have.

Paste the following code inside the file:

```javascript
// 404 Error Handler
function LostErrorHandler(req, res, next) {
	res.status(404);

	res.json({
		error: "Resource not found",
	});
}

// Exception Handler
function AppErrorHandler(err, req, res, next) {
	res.status(err.status || 500);

	if (err.authorizationError === true) {
		// Sets headers available in Authorization Error object
		res.set(err.authHeaders);
	}

	// `cause` is a custom property on error object
	// that may contain any data type
	const error = err?.cause || err?.message;
	const providedFeedback = err?.feedback;

	// respond with error and conditionally include feedback if provided
	res.json({
		error,
		...(providedFeedback && { feedback: providedFeedback }),
	});
}

module.exports = { LostErrorHandler, AppErrorHandler };
```

We have defined **two** functions here taking the signature of express middleware.<br />
_The first one_, **`LostErrorHandler()` function** is the _404 case handler_. Importantly, it sets a `404` status code on the response(`res`).

_And the second one_, **`AppErrorHandler()` function** has 4 parameters which distinguishes it as an **express error middleware**. This is the _General exception handler_.

Properties are available on the `err` parameter of the **`AppErrorHandler()` function** depending on _error constructor that created the Error object_. For example we see this line:

```javascript
// ...
if (err.authorizationError === true) {
	res.set(err.authHeaders);
}
// ...
```

We know `err` is an _authorization error_ object when we `throw` an exception using the custom `AuthorizationError` constructor, like:

```javascript
throw new AuthorizationError();
```

This will create an Error object that contains `authorizationError` property set to `true`. Also includes `authHeaders` property e.t.c.

## 3. Configure express application to use custom error handlers.

The last step is to configure the express application to use error handlers we have created. For this, open `index.js` which is the entrypoint to our application. This file should be located at `server/src/`.

Add the following code to this file:

```javascript
const express = require("express");

const {
	AppErrorHandler,
	LostErrorHandler,
} = require("./config/exceptionHandlers/handler.js");

/* 
  1. INITIALIZE EXPRESS APPLICATION 🏁
*/
const app = express();
const PORT = process.env.PORT || 8000;

/* 
  2. APPLICATION MIDDLEWARES AND CUSTOMIZATIONS 🪛
*/
// ...

/* 
  3. APPLICATION ROUTES 🛣️
*/
// Test route
app.get("/", function (req, res) {
	res.send("Hello Welcome to API🙃 !!");
});

/* 
  4. APPLICATION ERROR HANDLING 🚔
*/
// Handle unregistered route for all HTTP Methods
app.all("*", function (req, res, next) {
	// Forward to next closest middleware
	next();
});
app.use(LostErrorHandler); // 404 error handler middleware
app.use(AppErrorHandler); // General app error handler

/* 
  5. APPLICATION BOOT UP 🖥️
*/
app.listen(PORT, () => {
	console.log(`App running on port ${PORT}`);
});
```

In the **fourth part** of the snippet above, we have configured our app to handle _404 error case_ and _general errors_ that may occur from anywhere in the application.

**A few vital things to note:**

-   We have added error handling at _part4_ after routes for the application have been registered at _part3_. This way, incase of incoming request requiring resource on non-existent path, a 404 error handler will catch and process this error. And it is called **only after no route has been matched in the routes registered at _part3_**.
-   We have added _General error handler_ middleware as the **last-most** middleware in the express middleware chain. It is important to declare it last so that any unhandled errors that occur before it, can be captured and handled.

Hence when it comes to effective error handling in express, **order of placement of the error handlers is important**.

Cheers!🥂. Up to this point, your program should be equipped to gracefully handle unexpected errors that may occur in route handlers and middlewares.

Infact, let us test run by introducing error in our application.

## 4. Error Handling in action

To test Error Handling in our application, let's add another test route. So once again, open `index.js` file which should be found at the path: `server/src/`.

Edit _part 3 this file_ to add a new route, like shown:

```javascript
const CustomError = require("./config/errors/CustomError.js");

// ...

/* 
  3. APPLICATION ROUTES 🛣️
*/
// ...
// Test Crash route
app.get("/boom", function (req, res, next) {
	try {
		throw new CustomError("Oops! matters are chaotic💥", 400);
	} catch (error) {
		next(error);
	}
});

// ...
```

We have added a new route,(`/boom`) and its route handler.

**Note: _The route handler is written with the signature of express middleware, i.e it takes three parameters. Writing as an express middleware enables us to pass any errors generated here to the application's error handler we have configured using the `next()` function, which is available as the third parameter in the route handler._**

This route handler `throw`s an error inside a `try...catch` construct, using our predefined _`CustomError` class_. We have passed a **string message** and a **number for the HTTP status code** we would like to return in the response. This will create an error object that will be caught by `catch()`. Inside the `catch(){...}` block, we simply forward the caught error to our configured error handling middleware with a single line of code: `next(error)`. And that is it🦸.

Run the program. And when you run it, open your browser or any other client you prefer _e.g postman_. Then navigate to the route that throws an error, _i.e http://localhost:8000/boom_.

You should see that the error thrown in our application was handled deftly by error handler configured. And of course, our application is still running. It did not shut down.<br />
Notice that the **string message** and **HTTP status code** passed to `CustomError` constructor are included in the _response body and header_ respectively:

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ds9uwlm8knqfqsxy2m72.png" alt="Internally handled error response" />
  <figcaption>HTTP request/response made with <code>curl</code></figcaption>
</figure>

## Final thoughts

Well that is how you handle exceptions that can occur while running route handlers and middlewares in express. Possibly this is a compelling way since **it reduces boiler plate code you need to write in the `catch(){...}` block**, especially in the route handlers. Additionally, _"regular code"_ in route handlers is separated from _"error handling code"_.

Using _Custom Error constructors_ to create _Error objects_ when we `throw` is important for providing additional properties to the Error generated. The error handler can then obtain the properties on an error and respond to a user with concise information about what went wrong.

In the example where we test to see [error-handling in action](#4-error-handling-in-action), we wrapped logic for the route handler inside `try...catch` construct. If all we are going to write is **synchronous code only**, _then we **do not need to explicitly call `next(error)` function** with the error caught_ which is the case inside `catch(){...}` block. Therefore we can `throw` without the `try...catch` construct and Express will automatically pass the error to error-handling middleware. <small><em>But it is worthy to avoid writing code that is magical🪄.</em></small>

However if you write **asynchronous operations**, you must call `next(error)` function with the error returned, _so it may be caught by the error-handling middleware_. For example we may write a route handler that has asynchronous operation like this:

```javascript
app.get("/boom", async function (req, res, next) {
	const iAlwaysReject = new Promise((resolve, reject) => {
		setTimeout(() => reject("Operation failed!"), 2000);
	});
	try {
		await iAlwaysReject(); // Asynchronous OP
	} catch (error) {
		next(error); // Explicitly call next
	}
});
```

**Note:** _In Express 5 and above, asynchronous operations that reject or throw an error will call `next(error)` function automatically with the thrown error or the rejected value. If no rejected value is provided, `next` will be called with a default `Error` object provided by the Express router._ With above example, it means you can await without wrapping in `try...catch` construct nor calling `next(error)` explicitly. But why write code that is magical? 🤷‍♂️

Express ships with a default error handler. Of course it is not feature rich as you may want to create your own. I guess it is good enough to get you started.

Do you have other opinions? Drop them in the comment section🕳🤾. Meanwhile, I hope you found the article useful and...peace✌️.

---

_Follow me [@twitter](https://twitter.com/intent/user?screen_name=smitterhane). I share content that may be helpful to you😃._