Search code examples
node.jserror-handlingencapsulationpropagation

NodeJS Error Encapsulation


I am currently trying to handle exceptions and errors in a NodeJS app which will be used for critical information. I need a clean error management ! I've been wondering if there is something similar to Java Exceptions encapsulation.

I'm explaning.

In Java you can do something like that :

try {
    // something that throws Exception
} catch (Throwable t) {
    throw new Exception("My message", t);
}

That allows you to decide when to log your exception and you get the whole stack trace and call path !

I would like to know if there is a way to do the same in NodeJS because logging at every step seems not to be the right way of doing things.

Thank you.


Solution

  • I answer my own question to explain what i finaly did to have the wanted encapsulation. I used https://www.npmjs.com/package/verror as Sachacr suggested.

    Then I extended it that way :

    my_error.js :

    var VError          = require('verror');
    var _               = require('lodash');
    
    function MyError() {
        var args = [];
    
        var httpErrorCode;
        var cause;
    
        if (arguments.length > 0) {
            var lastArgumentIndex = [arguments.length];
    
            cause = manageCause(lastArgumentIndex, arguments);
            httpErrorCode = manageHttpCode(lastArgumentIndex, arguments);
    
            for (var i = 0; i < lastArgumentIndex; i++) {
                args[i] = arguments[i];
            }
        }
    
        this.__proto__.__proto__.constructor.apply(this, args);
    
        if (cause) {
            if (this.stack) {
                this.stack += '\n' + cause.stack;
            } else {
                this.stack = cause.stack;
            }
        }
    
        this.httpErrorCode = httpErrorCode;
    }
    
    MyError.prototype.__proto__ = VError.prototype;
    
    function manageCause(lastArgumentIndex, arguments) {
        if (lastArgumentIndex[0] > 0
            && arguments[lastArgumentIndex[0] - 1] instanceof Error) {
    
            lastArgumentIndex[0]--;
            return arguments[lastArgumentIndex[0]];
        }
    }
    
    function manageHttpCode(lastArgumentIndex, arguments) {
        if (lastArgumentIndex[0] > 0
            && _.isNumber(arguments[lastArgumentIndex[0] - 1])) {
    
            lastArgumentIndex[0]--;
            return arguments[lastArgumentIndex[0]];
        }
    }
    
    module.exports = MyError;
    

    It allows me to use it easily in my code :

    var MyError = require('./my_error.js');
    
    function withErrors() {
        try {
            // something with errors
        } catch (err) {
            // This is the same pattern as VError
            return new MyError("My message", err, 401);
        }
    }
    
    function somethingToDo(req, res) {
        var result = withErrors();
    
        if (result instanceof MyError) {
            logger.warn(result);
            res.status(result.httpErrorCode).send(result.message).end();
            return
        }
    }
    

    That way, i hace a nice stack trace with call path and every line involved in error/exception.

    Hope it will help people, cause i searched a looooong time :)

    EDIT : I modified my MyError class to add HTTP Error codes and clean arguments management.