Error Handling in Express.js
Tags: webdev, tutorial, express, programming
Published: 2023-01-08 21:31:26

Topics:
1. [Before we start](#beforewestart)
2. [Motivation](#motivation)
3. [Let’s build a server!](#letsbuildaservice)
4. [Error handling & middlewares](#errorhandlingandmiddlewares)
5. [The Error object](#theerrorobject)
6. [Custom Errors](#customerrors)
7. [Conclusion](#conclusion)

## 1. Before we start<a name="beforewestart"></a> ##
Error and exception handling is a topic that every developer, beginner or advanced, finds himself tackling almost all the time. There are many ways to avoid exceptions from crushing our server, but many of them aren’t letting the developer have full control of the structure and timing of the error thrown. In this tutorial, I will guide you through a simple, modular and maintainable way to handle errors and exceptions in Express server.

before we start, one important note – this tutorial is not for absolute beginners. You will need to have basic knowledge of Node.js, Express server, npm, and using Postman to send basic http requests. You will also need to have them installed on your local machine.

## 2. Motivation<a name="motivation"></a> ##
Obviously, in a basic Node.js http server, when an exception is thrown without being handled, the server crushes and our service is down. No developer wants this. Also, sometimes we do catch the error with a try catch block, but it’s hard to know what is causing it, and if or how we can handle it. So, let’s make a basic server and then move on to better understanding errors.

## 3. Let’s build a server!<a name="letsbuildaservice"></a> ##
We build our Node.js server with Express. Express is a fast, unopinionated, minimalist web framework for Node.js. 
So let’s initialize our project and then add Express. 
`npm init -y`
`npm install express`

We’ll also need Nodemon to restart our server on every change. 
`npm i nodemon`

And to set it up you we’ll need to add the following line to our `scripts` object inside `package.json` file.
`“start”:”nodemon index.js”`

Now, add this code to your index.js file:
```javascript
// index.js
const express = require("express");
const app = express();
const port = process.env.PORT || 3000;
 
app.get("/", (req, res) => {
  console.log("I'm a service being called");
  console.log("Now I am going to throw an error, because something went wrong");
  throw new Error();
});
 
app.listen(port, () => {
  console.log(`Server is listening on port ${port}...`);
});
```
Our root route simply `console.log` the incoming requests.
To start the server: 
`npm start`

## 4. Error handling & middlewares<a name="errorhandlingandmiddlewares"></a>##
What is a middleware in Node.js? Middleware comes in the middle of the request and response cycle of the Node.js execution. It also provides access to many functions like request and response objects with the Next function of the cycle. In this tutorial we will make an error middleware to handle our errors.

If we run this server and send a `GET` request to  http://localhost:3000 the server will crash. It happens because the error is thrown but not handled by any function. let’s add another package called `express-async-errors`.
`npm i express-async-errors`

 This package does two things:
* wraps the  function in a try/catch block under the hood, so we don’t need to do it explicitly every time.
* In the virtual catch block, it calls next(error). The error is caught and passed to the next middleware.

So, to catch the `next(error)`, let’s create an error handling middleware.
Create a new folder- `middlewares`, inside this folder create a new file called `errorHandler.js`. Then copy-paste these lines:
```javascript
// middlewares/errorHandler.js
exports.errorHandler = (error, req, res, next) => {
  res.status(error.status || 500);
  res.json({ message: error.message || "Internal Server Error" });
};
```
The first parameter is the error thrown, then the req and res objects, and next is the last one. The service catches the error and returns it as a response, or returns a default error message. 
Now let’s import the handler on the top of the server file , and add it as an Express middleware. Notice that the handler is placed at the end of the server routes, so when `next(error)` is called, it will be caught by this error handler.
The updated server:
```javascript
// index.js 
const express = require("express");
const { errorHandler } = require("./middlewares/errorHandler");
const app = express();
const port = process.env.PORT || 3000;
 
app.get("/", (req, res) => {
  console.log("oh no something went wrong 😵‍💫");
  console.log("I throw an error, because something went wrong");
  throw new Error();
});
 
app.use(errorHandler);
 
app.listen(port, () => {
  console.log(`Server is listening on port ${port}...`);
});
```
If we run the server and send a request the server will not crush and you’ll get the following message on postman:


![postman message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u3j9bjr3s1uodsk322va.png)
Notice the 500 status code:

![postman status](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmh4qp41wbv5wjv480je.png)
We got the default error we set inside the error handler. Let’s continue and learn about the Error object, and return custom errors in the response.

## 5. The Error object<a name="theerrorobject"></a> ##
We can talk a lot about Node.js Error object, but let’s talk about the most common properties: `name` and `message`.
Here’s an example:
```javascript
class Error {
  constructor(message) {
    this.message = message;
  }
}
 
const error = new Error("this is the message");
error.name = "errorName";
 
console.log(error.name); //errorName
console.log(error.message); //this is the message
```
An error object can take a message, and it’s name can be set afterwards. This will be important when we’ll go on and create some Error objects of our own on the next step.

## 6.Custom errors<a name="customerrors"></a> ##
Let’s consider the `404 – Not Found` status code. We might want it to appear on many occasions – when a property is missing from a request, or when we did not find an entity in the database. We will need to create an error for every use-case in which we expect an error in our code, so we will be able to determine where the error occurs, and what caused it.

Now let’s implement this. Create a new folder called “errors”. Inside it, create a file called `NotFoundError.js`. inside it, create a class called `NotFound` like so:
```javascript
//errors/NotFoundError.js 
class NotFound extends Error {
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    this.status = 404;
  }
}
```
The `NotFound` class inherits the Error class and adds some properties of its own:
* **Status** – we wanted to consider the 404 status, so the class will have it as a property
* **Name** – in this example, the name property will hold the name of the class.

But this is not enough, right? 404 status can occur in our code for many reasons that we probably want to tell apart from each other. This is where the magic happens. We can continue and create custom errors that inherits this basic `NotFound` class, and specify the exact reason the error has occurred, for example:
```javascript
// errors/NotFoundError.js
class NotFound extends Error {
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    this.status = 404;
  }
}
 
class EntityNotFound extends NotFound {
  constructor(entity) {
    super(`${entity} not found...`);
    this.name = this.constructor.name;
    this.entity = entity;
  }
}
 
class PropertyNotFound extends NotFound {
  constructor(property) {
    super(`Property: ${property} not found...`);
    this.name = this.constructor.name;
    this.property = property;
  }
}
 
module.exports = { EntityNotFound, PropertyNotFound };
```
Now we can use a custom error, with the same status code as the base error we made, in order to send a specific response. If the error is an entity we did not find, we can use the `EntityNotFound` class, pass it an entity name, and get specific information about the error.
Let’s extend our basic server and try this out:
```javascript
// index.js 
const express = require("express");
const { errorHandler } = require("./middlewares/errorHandler");
const {
  EntityNotFound,
  PropertyNotFound,
} = require("./errors/NotFound.errors");
const app = express();
const port = process.env.PORT || 3000;
 
app.get("/", (req, res) => {
  console.log(
    "I'm a service trying to access the req.params.id from the request"
  );
  throw new PropertyNotFound("id");
});
 
app.get("/user", (req, res) => {
  console.log("I'm a service trying to find a user entity in the db");
  throw new EntityNotFound("user");
});
 
app.use(errorHandler);
 
app.listen(port, () => {
  console.log(`Server is listening on port ${port}...`);
});
```
If you’ll run the server now and make the above calls, the server will still run, and you’ll get a custom message from each middleware.

## 7. Conclusion <a name="conclusion"></a>##
Error handling is very important while you write your application, especially when you establish a Node.js server. Using an error handler and custom errors can improve your API response clarity, and make a more reliable and stable server, in a simple and elegant way.
what do you think? leave your comments 🙂