Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node.js - Error handling different types of errors

I'm writing a series of REST APIs in Express and want to write a robust and consistent way of handling errors and presenting them to the user. So far I'm using middleware that looks like the following:

app.use(function(req, res, next){
    res.render('404', { status: 404, error: 'not_found', error_description: 'the url '+req.url+' could not be found' });
});

app.use(function(err, req, res, next) {
    switch (err.name) {
        case 'CastError':
            res.status(400);
            return res.send({code:400, error: 'cast_error', error_description: err});
        default:
            console.log(err);
            return res.send({code:500, error: 'internal_error', error_description: 'something went horribly wrong!'});
    }
});

Now the problem comes in that errors can come from any part of the application. For example, Mongoose fires errors like 'CastError', there might be general system errors (unable to connect to the database) and there's also user validation errors.

Now some errors I want to present a message to the user (for example validation errors or telling them what was wrong with their API request), whereas others I want to hide from the user.

So looking at a validation error:

throw new Error('not a valid project id');

At the moment that'd just get caught as a generic 500 error and no useful message presented to the user. How can I differentiate the above error from a general system error so they can be handled differently? Is there an error type property I can make use of (perhaps err.name). If so, how do I use it?

Concept ideas (that obv don't work):

throw new Error('validation', 'not a valid project id');

Or

throw new Error('not a valid project id').name('validation');
like image 442
richwol Avatar asked Feb 17 '15 13:02

richwol


People also ask

How many types of errors are there in node js?

An error in Node. js is any instance of the Error object. Common examples include built-in error classes, such as ReferenceError , RangeError , TypeError , URIError , EvalError , and SyntaxError .

What are the different types of errors in JavaScript?

There are three main types of errors that can occur while compiling a JavaScript program: syntax errors, runtime errors, and logical errors.

What is error handling in Node JS?

Error handling is the process of catching and processing errors efficiently. These errors may be synchronous or asynchronous. Error handling is a core part of any programming language. As we know node.js is nothing but the JavaScript runtime for the server. Node.js Mainly works on how we handle errors coming in a flow.

Should you throw error objects in Node JS?

We hope that was a useful introduction to error handling in Node.js. At this point, you should feel more comfortable with the idea of throwing error objects and catching them in either synchronous or asynchronous code. Your applications will be significantly more robust and ready for production.

Why should we be savvy with our node error handling?

Furthermore, it’s not just the user experience that dictates why we should be savvy with our Node.js error handling. If we want our program to be secure, resilient, high-performing and bug-free, Node.js error handling is a must.

Why is it important to write descriptive errors in Node JS?

With anyone in the world throwing requests at our program, it’s only a matter of time before values get into our program that we didn’t expect. And when we get these values, effectively responding to our users means being as descriptive as possible about the error. If we don’t have proper Node.


2 Answers

Errors are objects and can be assigned additional properties. You could add more properties to an error after it has been constructed. Also note that the operand to throw doesn't have to be an Error, it can be any other object.

var validationError = new Error('Not a valid project ID');
validationError.type = 'validation';
throw validationError;

A better alternative is to use a custom error class inheriting from Error.

function ValidationError(message) {
    if(!(this instanceof ValidationError)) {
        return new ValidationError(message);
    }
    var err = this.err = Error.call(this, message);
    this.message = message;

    Object.defineProperty(this, 'stack', {
        get: function () {
            return err.stack; 
        }
    });

}
ValidationError.prototype = Object.create(Error.prototype, {constructor: ValidationError});

This approach lets you distinguish ValidationErrors from other errors by using the instanceof operator. This is an excerpt from a koa application:

app.use(function *() {
    try {
            if(this.method != 'GET') {
                yield this.connection.beginTransaction();
                yield *next;
                yield this.connection.commit();
            } else {
                yield *next;
            }
        } catch(err) {
            if(err instanceof ValidationError) {
                this.body = err.message;
                this.status = 422;
            } else {
                throw err; //let the framework notify the client of 500 Internal Server errors
            }
            if(this.method != 'GET') {
                yield this.connection.rollback();
            }
        }
});
like image 159
c.P.u1 Avatar answered Oct 16 '22 14:10

c.P.u1


You should consider using an existing npm module such as http-errors or boom. At least when throwing your own errors, these will make it easy to get good HTTP semantics in your responses.

like image 33
Peter Lyons Avatar answered Oct 16 '22 14:10

Peter Lyons