Errors need to be handled in such a way that no sensitive data gets out to the public. For example, if you enter the wrong login credentials on some websites, you may receive an error message which says “Wrong email or password”. Instead of telling which one is wrong they tell you that either can be wrong.
Expressjs has a built-in error handler so you don’t need to do the heavy lifting.
In an empty folder, run npm init -y and then run npm i express to initialize the node project and install express.
Then, create a file called index.js i and paste the following code. This should be your root folder.
1
2
3
4
5
const express = require('express');
const app = express();
app.use(express.json());
app.listen(3000, () => console.log('server running on port 3000'));
Errors in synchronous code are not very common and mostly occur due to logical issues. Express is able to handle it perfectly all by itself, so there is no need to do anything here. For example, if we create the following API,
1
2
3
app.get('/', function (req, res) {
throw new Error('BROKEN')
})
making a request to this route will give you the following output:
As you can see, an error is shown in the console. The client-side also gets notified of this.
This was the default error handling in express, which is built in. It works fine in the case of code that is synchronous. But with asynchronous code it’s not so graceful.
Error handling in asynchronous code:
You have likely used the *next()*function in middleware, it is a function that gets called when middleware wants the next function in the call stack to be called.
If any parameter is passed to this next() function, express treats it as an error. For example, create the following API. If there is no msg object in the body then it is passing a value called “no msg” to the next function, which will treat it as an error message.
1 2 3 4 5 6 7 8 9 10
app.post('/', (req, res, next) => { const { msg } = req.body; if (!msg) { next('no msg') } else { res.send('msg') } })
On making a request to this API, you can see the following result in the postman’s preview tab. Because this was passed to next() as a parameter.
This is an HTML page showing the error message.
This was a very basic way to show some error occurred, but what if you want to show a more custom error with a custom message and status code? For this, we will be creating an error class. Create a folder called error in the root folder and create a file called ApiError.js in it with the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class ApiErrorClass {
constructor(statusCode, msg) {
this.statusCode = statusCode;
this.msg = msg;
}
static invalidRequest(msg) {
return new ApiErrorClass(400, msg);
}
static internalError(msg) {
return new ApiErrorClass(500, msg);
}
}
module.exports = ApiErrorClass;
Now we will create functionality to utilise this class, create a file in the same folder called errorHandler.js and post the following code. In express, error handlers are supposed to have four arguments, which are in the order as shown for the following function.
1
2
3
4
5
6
7
8
9
10
11
12
13
const ApiErrorClass = require('./ApiError');
function errorHandler(err, req, res, next) {
console.log(err);
if (err instanceof ApiErrorClass) {
res.status(err.statusCode)
.json(err.msg);
return;
}
res.status(500)
.json('something went wrong');
}
module.exports = errorHandler;
All that is left now is to instruct express to use it as the default error handler.
Modify the API in the following way while also adding these two lines.
1 2 3 4 5 6 7 8 9 10 11 12
const errorHandler = require('./error/errorHandler'); app.post('/', (req, res, next) => { const { msg } = req.body; if (!msg) { next(ApiErrorClass.invalidRequest('Msg not present')); } else { res.send(msg) } }) app.use(errorHandler);
Make sure to define the error handler last, which means that after all the app.use() statements are written then you will write the statement to use the error handler.
Let’s see our functionality in action now. Our API will throw an error if there is no msg key in the body attribute, so make a request to this API without an empty body. Following is the response in postman.
Now, let’s make a valid request. Send the following data in the request body.
1 2 3
{ "msg": "Message" }
In response, we will get:
The server should return status codes 200 - 299 if the code did everything it was intended to do. Otherwise, if the client made an invalid request or sent some invalid data to the server, then status codes from 400 - 499 will be sent. And, if there was an error from the server side, status codes from 500 - 599 will be sent. You can read more about the status codes here.
For example, a status code shows that something was not found. In order to send this error with the required status code, you can do this:
res.status(404).send('Resource not found');
If you want to send the errors in the form of JSON objects, which are easier to handle in the frontend, you can modify the ApiErrorClass like this.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const ApiErrorClass = require('./ApiError');
function errorHandler(err, req, res, next) {
if (err instanceof ApiErrorClass) {
res.status(err.statusCode)
.json({
error: err.msg
});
return;
}
res.status(500)
.send('something went wrong');
}
module.exports = errorHandler;
Notice how now the response is an object. If we now make an invalid request,
1 2 3
{ "error": "Msg not present" }
this is what we will see, and we can add as many JSON keys as we like.
Just like any other middleware you can have multiple error handling middlewares. Let’s say you have an error handling middleware set up just like the previous one, named ErrorHandlerTwo, you can use it using the following line.
app.use(ErrorHandlerTwo);