Global Error handling in Node Js

Global Error handling in Node Js

Error handling in Node js is one of the most important things to know as a developer using NodeJS to build amazing software.

In this article, I will be showing you how to handle errors in NodeJS and also creating a global error handler to handle unforeseen errors when you ship products from the development environment to the production environment.

Table of Content

  • What are Errors
  • Types of Errors in Node.js
  • How to Handle Errors
  • Create a Global Error Handler
  • Resources

What is an Error

An error is described as an action that is incorrect or inaccurate. In some cases, an error is synonymous with a mistake but in software development, it can be referred to as a bug. Errors in software development can be operational or logical errors during development or in the production environment.

Types of Error in NodeJS

  • Logical Error
  • Operational Error

Programmer Error

This is an error that occurs within codes that are either poorly written or unstructured which can be called a bug. An example of a logical error is when you are trying to access a variable that returns undefined after compilation might result in a logical error and that has nothing to do with run time or system environment, passing a “string” where an object was expected, calling an asynchronous function without a callback.

Operational Error

This is a runtime environment problem. It's a type of error in NodeJs that has nothing to do with code, for example, when a memory is exceeded, request timeout, invalid user input, failed to connect to a server, etc

How to Handle Errors

Errors can be handled using the callback approach or the async / await approach where you make use of the try{} catch(err){} block.

An example of handling an error using callback

const fs = require('fs');

fs.readFile('/foo.txt', function(err, data) {

// If an error occurred, handle it // throw
  if(err) {
    console.log('Error');
    return;
  }
  // Otherwise, log the file contents
  console.log(data);
});

An example of handling an error using promises or async / await

exports.findMoviesService = async () => {
try{
  const movies= await MovieModel.find()
   return movies;
} catch(err){
console.error(error); //log Error
// Or create an error middleware
 }
};

Although I would advise you to make good use of the promises or async / await approach by utilizing the try{} catch(err){} which saves you a lot of time including callback hell.

Using ExpressJS handles errors that occur in synchronous code inside route handlers and middleware without extra work. If synchronous code throws an error, then Express will catch and process it.

For example:

app.get('/movies', function (req, res, next) {
  throw new Error('Error') // Express will catch this on its own.
})

For errors returned from asynchronous functions invoked by route handlers and middleware, you must pass them to the next() function, where Express will catch and process them.

For example:

const fs = require('fs');

app.get('/cards', function (req, res, next) {

  fs.readFile('/file-does-not-exist', function (err, data) {

    if (err) {

      next(err) // Pass error to Express

    } else {

      res.send(data)

    }
  })
})

You can check out the official Express doc to read more.

Create a Global Error Handler

In one of the examples shown above, I wrote a console.log to log error whenever it's encountered which might not be appropriate when the application is deployed to the production environment but there is a suggestion to create a middleware that can handle the errors. I will show you how to write or create your own error middleware. Example:

// Handle errors appropriately
exports.errorResponse = (res, message, statusCode = 500, error = {}) => {
  res.status(statusCode).json({
    success: false,
    message,
    error: {
      statusCode,
      message,
      error,
    },
  });
};

// you can call the function as shown below
// Passing the response object, message, status code, and success action
errorResponse(res, 'Not found', 404, false);

Now, how about some errors that refuse to be caught? funny right? Of course, there is some error that might be unforeseen but you need to make sure your application handles everything in a manner that the error does not break your working application in production.

Example: In your app.js or server.js

// This should be the last route else any after it wont work
app.use('*', (req, res) => {
  res.status(404).json({
    success: 'false',
    message: 'Page not found',
    error: {
      statusCode: 404,
      message: 'You reached a route that is not defined on this server',
    },
  });
});

Looking at the above example, you can see that it's similar to the error middleware we created earlier that returns the error message, status code, and successful action.

Resources

Cover image

Error

ExpressJs Error