DEV Community

Cover image for Central Error Handling in Express

Central Error Handling in Express

Chinedu Orie on July 15, 2019

Express is a fast, unopinionated, minimalist web framework for Node.js - docs Error handling is a routine that one can not do without while buil...
Collapse
 
jakub41 profile image
Jakub

Hello,
I really like this post as I'm learning a better way of handling errors.

I have a question about when you add in the .catch(err) { next(err) }
Is this actually throwing out an error from server or I should still use like you did before
throw new ErrorHandler(500, 'Internal server error');

Or that next(err)is doing it?

I just not get that and I would like to understand it.

I have an example of how I used:

async getAll(req, res, next) {
        try {
            const profiles = await db.Profile.find({});
            if (!profiles)
                throw new ErrorHandler(404, "No profiles are found!");

            res.send({
                profiles
            });

            next();
        } catch (err) {
            next(err);
        }
    },

Thanks for help :)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
trannguyen61 profile image
trannguyen61

Since getAll is a middleware, it must call next() to tell the server to continue processing the next step after that, or else it will be blocked and never return any responses to the client. The error thrown in try block is then caught in catch block, through the name of err.
Therefore, calling next(err) means passing err to the next error-handling middleware while keeping the flow of your app running.

Collapse
 
briantuju profile image
Brian • Edited

The best error handling mechanism I've seen so far. I have a question though.

I understand that i have to require this in the index file:

const { handleError } = require("path-to-code")

Will I have to include this code

const { ErrorHandler } = require("path-to-code");

in every file where I need to handle errors apart from the index file?

Collapse
 
nedsoft profile image
Chinedu Orie

It's like any other module, you will have to require/import it anywhere you need to use it. No specific exceptions, it depends on the use case.

Collapse
 
briantuju profile image
Brian

Thank you so much

Collapse
 
maxiqboy profile image
Thinh Nguyen • Edited

Great Article, Thanks

btw, I got a small question in this own Error class :

class ErrorHandler extends Error {
  constructor(statusCode, message) {
    super();
    this.statusCode = statusCode;
    this.message = message;
  }
}
module.exports = {
  ErrorHandler
}
Enter fullscreen mode Exit fullscreen mode

Why we have to write like this (1)

super();
this.message = message;
Enter fullscreen mode Exit fullscreen mode

but not like this (2)

super(message);
Enter fullscreen mode Exit fullscreen mode

?

Actually, I wrote like (2) and then my own class lost a message property

It only comes back when I change it to (1).

What is the difference between them ?

Thanks,

Collapse
 
nedsoft profile image
Chinedu Orie • Edited

The super() method is used when a class (child) inherits from another class (parent).
The super() method provides a means of syncing the child's constructor to the parent's constructor.
Let me illustrate with an example

class Foor {
    constructor(name) {
        this.name = name
   }
    printName = () => {
      console.log(this.name);
   }
}

class Bar extends Foo {

     constructor(name) {
         super(name)
   }
}

const bar = new Bar('Test');

bar.printName() // Test
Enter fullscreen mode Exit fullscreen mode



Now, looking at the code above,
Foorequires anameto be passed to its constructor in order to function, whenBarinherited fromFoo, there's no way thenamecould be passed down toFooif not with thesuper()`

So, in relation to the snippet that you shared above, you are passing the message to the parent which in this case is Error, that way the child ErrorHandler has no access to message

I hope this helps.

Collapse
 
peacefulseeker profile image
Alexey Vorobyov

Is there a necessity in Bar constructor at all?
You just pass the same Test value to the parent class ultimately. In this case
there is no need to a constructor at all I assume and Eslint should also hint about it.

Collapse
 
mr_cea profile image
Ogbonna Basil • Edited

This is cool,

Just one opinion, i feel it should be expanded to be not just Error Handler but statusHandler

```
class statusHandler extends Error {
constructor(statusCode, message, data) {
super();
this.statusCode = statusCode;
this.message = message;
this.data = data || null

}
}
module.exports = {
statusHandler
}




Likewise for handleError but generally this approach is effectively DRY. Nice one
Collapse
 
nedsoft profile image
Chinedu Orie

Just like Express is unopinionated, how you apply the concept in the article is also unopinionated. And except I do not understand you clearly, it'd not make sense semantically to throw a success response as an error. Thanks for sharing your views.

Collapse
 
kopax profile image
Dimitri KOPRIWA

Hi and thanks for this article, I have tried to implement it and instead of having the errorMiddleware called when I throw new ErrorHandler(500) within my route, I have in the console: (node:16482) UnhandledPromiseRejectionWarning: Error: Server Error what part did I miss? thanks

Collapse
 
oim5nu profile image
Yuanpeng Zheng

Great post. Buddy. Just got one question here.

const validateUser = async (req, res, next) => {
  try {
    .....
    next()
  } catch (error) {
    next(error)
  }

  res.on('finish', () => {
     // How could you handle the error here for express? Thanks. 
  }
}
Collapse
 
ajaysainy profile image
Ajay Sainy

Thanks for a useful post. One question on usage of validateUser method. How do we use that method in lets say any PUT path that validates a user?
Simply calling validateUser(req, res, next) is causing the error Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client in the code below validateUser call that assumes the user is already validated.

I am guessing this is happening because express does not immediate terminates the request processing after the response has been sent to the client.

Collapse
 
nedsoft profile image
Chinedu Orie

I think your guess is right. Sometimes it happens if a return statement is skipped somewhere, so the execution continues after the first error encounter

Collapse
 
rodrigoabb profile image
Rodrigo Abbás • Edited

Hi Chinedu,

Thank you very much for your post! This is what I've been wanting to implement, but somehow I couldn't figure out a simple way.
I adapted it a little bit to my code but applied the same principle you are describing.
Again, thanks man!
Cheers!

Collapse
 
algol007 profile image
Ady Rahmansyah

Thank you. It's really helpful

Collapse
 
rajeshbarik66 profile image
Rajesh Barik

Hi, This is an awesome article. I just have one problem. I implemented it, but whenever I use this throw error, my server crashes with error throw er; // Unhandled 'error' event. What did I do wrong ? Could you please help me ?

Collapse
 
leivermoreno profile image
Leiver Moreno • Edited

Just what I was looking for, I'm learning Express.
Just one doubt, what in case of, for example, a database error? Which is no enclosed by an if statement and there is no error throw for it. Therefore the express error middleware is called and ErrorHandler object is instantiated with code and message set to undefined.

The solution I propose is to add an if statement in the ErrorHandler constructor to check if the given values are undefined. Let know your opinion and if I'm wrong.

Collapse
 
omancoding profile image
OmanCoding

Thank you for the article, I learned something.

I have question, how does Express know that next(error), should be passed to the Error Handling middleware (which has 4 arguments)?

If there is a middleware that has (res, req, next) that was sat up before the Error Handling middleware, will it get first to handle the error?

Nasser

Collapse
 
leivermoreno profile image
Leiver Moreno • Edited

This happens because even if you do not configure a middleware for error handling, express does it internally for you, so when an error occurs, all subsequent middlewares are skipped until the error handling middleware. How does express know what this middleware is? Because it has four arguments, error, req, res, next.

Collapse
 
rejaulkarim profile image
Rejaul Karim 🔥

what about global error? you code din't handle global error?

Collapse
 
chan_austria777 profile image
chan 🤖

exactly what i was thinking. I feel like all uncaught exceptions won't be created as a custom Error

Collapse
 
taniarascia profile image
Tania Rascia • Edited

This is great, thank you! Exactly what I needed.

Collapse
 
nedsoft profile image
Chinedu Orie

Glad to learn you found it helpful. ✌️

Collapse
 
ogwurujohnson profile image
Johnson Ogwuru

This is some good stuff, mate

Collapse
 
nedsoft profile image
Chinedu Orie

Thanks Chief

Collapse
 
jorgee97 profile image
Jorge Gomez

Thanks for the article Orie, it really help me a lot.

Collapse
 
areljannc profile image
AJ Clemente

This is it, chief. This is exactly what I'm looking.

I've been trying to figure out to make our back-end code cleaner and I think this post has answered all of my questions.

Thank you and take care!

Collapse
 
nedsoft profile image
Chinedu Orie

Glad to hear that you found it helpful

Collapse
 
klevamane profile image
Richard Onengiye

Awesome Awesome stuff....

Collapse
 
nedsoft profile image
Chinedu Orie

Thanks!

Collapse
 
hirengohil13 profile image
Hiren Gohil

ReferenceError: ErrorHandler is not defined

const { handleError, ErrorHandler } = require('./helpers/error')
Imported ErrorHandler but not used into Index file.

Collapse
 
yuriytigiev profile image
YuriyTigiev

Why for a success case the last step is next(), but not a return res.status(200)?

Collapse
 
nedsoft profile image
Chinedu Orie

It's because, the function is a middleware, not a final destination, with next() returned, it would proceed to the next code to be executed.

Collapse
 
minemaxua profile image
Maksym Minenko

Maybe super(message) instead of just super()?

Collapse
 
iamdjarc profile image
IG:DjArc [Hey-R-C]

Hey Chinedu, thank you for this article. I have a question on Testing.

How do you actually test the: "next(error)" I am using nest and I am having a hard time capturing that.

Thank you.

Collapse
 
javabytes profile image
JavaBytes

Thank you so much for this article! it was very clear and well explained each step of the way. Very helpful!

Collapse
 
manoellribeiro profile image
Manoel Ribeiro

It's a really nice content, thank you for the help!!

Collapse
 
hirengohil13 profile image
Hiren Gohil

Nice Article

Can we make common structure for Error & Success both ?

Collapse
 
muhammadahmed8 profile image
Muhammad Ahmed

Hello, nice post. If I use express-validation, how could I throw my custom error class from express-validation? Thank you.