Global Error Handling
Tags: node, javascript, express
Published: 2020-04-07 17:41:36

There are several ways to handle error in Node application with express server in action, most famous of them is using `try catch` block
```js
try {
  // some async code/execution
   } catch (err) {
  // throwing error like
  res.status(error_code).json({
     success: false,
     error: "any_custom_error_message" || err.message
  })
}
```

###-:Issues with this approach:-###
Usually in applications we have some very common errors which are appearing due to very same reason in multiple functions. Some examples are 
1. Invalid object_Id (Cast Error)
2. Duplicate key (Duplicate entry/ unique field restraint)
3. Validation Errors (required field error)

Usually validation errors appear due to restraints which we put on keys in our model. 
```js 
name: {
      required: [true, "Name is required}
      }
```

###-:What we are going to do:-###
We are going to make a global error handler which will handle these repeatedly occurring errors in a very DRY(Do not repeat yourself) way. 
Steps we are going to follow
1. We are going to make an ErrorResponse class
2. We will pass err to the next function like `next(err)`
3. We will make a middle-ware function which will handle these errors

-:Lets do some code:-
```js
class ErrorResponse extends Error {
  constructor(message, statusCode) {
    super(message); // we do this because Error class has its own error.message property and we are going to pass our message to that property
    this.statusCode = statusCode;
  }
}

module.exports = ErrorResponse;
```
You can create this class in utils or any helper folder. basically this will instantiate the global Error class of Javascript with our own custom message and status code. 

Now second step is to make a `error.js` middle-ware which will handle responses on `err` properties like
```js
const ErrorResponse = require("../utils/errorResponse");
const errorHandler = (err, req, res, next) => {
  let error = { ...err };
  error.message = err.message;
  // Log to console for developers
  console.log(err.stack.red);

  // Mongoose bad ObjectId
  if (err.name === "CastError") {
    const message = `Resource not found with id of ${err.value}`;
    error = new ErrorResponse(message, 404);
  }

  // Mongoose duplicate key
  if (err.code === 11000) {
    const message = "Duplicate field value entered";
    error = new ErrorResponse(message, 400);
  }

  // Mongoose validation error
  if (err.name === "ValidatorError") {
    const message = Object.values(err.error).map(val => val.message);
    error = new ErrorResponse(message, 400);
  }

  res.status(error.statusCode || 500).json({
    success: false,
    error: error.message || "Server Error"
  });
};

module.exports = errorHandler;
```
This is basically going to handle those three most repeatedly occurring responses on the base of `err.name` and `err.code` properties.

Third step is to change your controller methods like
```js
try{
   //async code
} catch (err) {
   next(err)
}
```

and in the end mount `error.js` middle-ware after `app.use(routes)` 

Now you don't need to handle these three most commonly occurring errors again and again in your controller functions. You can also use ErrorResponse class to handle case of no resource found and any other function.
```js
if (!resource)
      return next(
        new ErrorResponse(`Resource not found with id of ${req.params.id}`, 404)
      );
```