Javascript – Node.js error handling through each layer

designerror handlingjavascriptnode.js

I am looking for a way to handle errors in a Node.js application without getting lots of log entries for the same error event, one from each each affected layer.

This might actually apply to any language, but I still don't understand how to do it correctly. The questions are always who handles the errors, does it make sense to continually throw to the top, and who logs what?

Let's take a simple example of a user system where you can retrieve users from a database and "log in" if credentials match.

Database layer

// connects to a mongo db 
class UserDatabase(){
   async getUser(filter){
       // this can throw if connection is dead
       let user = await this.collections.users.findOne(filter);
       return user;
   }
}

Application layer

// makes calls to the db class to "login" a user
class UserApp {
    async loginUser(email, password){
       let user = await this.db.getUser({email});
       if(!user){
           return false;
       }
       if(user.password === options.password){
           return true;
       }
    }
}

REST layer

// calls the API from REST calls
class UserRestApi {
    async loginUser(request, response){
        let result = await this.app.loginUser(request.body.email, request.body.password);
        if(result){
            response.status = 200;
        }
        else {
            response.status = 401;
        }
        response.end();
    }
}

At this moment there is 0 error handling. We can fail almost everywhere with uncaught exceptions. But is there ever any point in catching at the lowest level? Suppose getUser() fails because the mongodb connection dies. I can catch it and log it there, but then do I throw it again, and again, and again, and log it again, and again, and again? Does that make sense? I would end up in this case with 2-3 repeated logs.

I'm just not sure how to approach this.

Best Answer

General Principles of Error Handling

Exceptions should be handled in the layer of code that can actually do something about the error.

The "log and rethrow" pattern is often considered an antipattern (for exactly the reason you mentioned, leads to a lot of duplicate code and doesn't really help you do anything practical.)

The point of an exception is that it is "not expected". If the layer of code you are working in can't do something reasonable to continue successful processing when the error happens, just let it bubble up.

If the layer of code you are working in can do something to continue when the error happens, that is the spot to handle the error. (And returning a "failed" http response code counts as a way to "continue processing". You are saving the program from crashing.)

Node.js web server error handling (using a library like Koa/Express)

I would strongly recommend using a framework like Koa.js (the "successor" to the very popular Express framework) if you are building an http server in Node.js.

These frameworks give you a very clean and simple toolset to build up your webapi with ease. (and they both give you default error handling out of the box)

Related Topic