6

I'm building an API (using Expressjs v4) and typically I've dealt with errors within the route rather than using middleware. For example:

router.use('/', function(req, res, next) {
  ...
  if (err)
    return res.status(500).send({type: "serverError", message: "Something has gone wrong on our end."});
}

I now realise that middleware is the "way to go." I've seen the rather limited documentation on the Expressjs site here: http://expressjs.com/guide/error-handling.html but still unsure of a few things.

I've added in the server.js:

function errorHandler(err, req, res, next) {

}

but how do I supposed to handle the different types of errors (400,404,500 etc)?

I'm finding myself writing 3 lines of code each time an error occurs:

//A route
var err = new Error();
err.status = 404;
return next(err);

and I can access the status using:

function errorHandler(err, req, res, next) {
  console.log(err.status);
  if(err.status == "400")
    //do something
  else
    //etc etc
}

Surely there's an easier way than this? Am I missing something?

tommyd456
  • 10,443
  • 26
  • 89
  • 163

2 Answers2

4

Instead manually creating error, you can delegate that error like below.

return next(err);

And your error will go deep down all the routes defined until it find routes with below signature.

app.use(function (err, req, res, next) {

});

You can see the err argument in above route.

Ideally you can use below two methods for both DEVELOPMENT & PRODUCTION environment.

if (process.env.NODE_ENV === 'development') {
    app.use(function (err, req, res, next) {
        res.status(err.status || 500);
        logger.log('info', err.message + " expected URL was " + req.url);
        res.status(err.status).send(err.status, {
            message: err.message,
            error  : err
        });
    });
}

app.use(function (err, req, res, next) {
    res.status(err.status || 500);
    logger.log('error', err.message + " expected URL was " + req.url);
    res.status(err.status).send(err.status, {
        message: err.message,
        error  : {}
    });

});

You can capture actual populated error object in there.

Palak Bhansali
  • 731
  • 4
  • 10
  • 1
    but the `err` won't have `status` though will it unless I manually set it as in my question right??? - and those three lines I'm trying to avoid because I will have to do this for every error. – tommyd456 Dec 03 '14 at 17:58
  • Not every error comes with status. but you are using [callbacks](https://www.joyent.com/developers/node/design/errors) or aren't you ! – Palak Bhansali Dec 03 '14 at 18:05
  • Yeah I'm using callbacks – tommyd456 Dec 03 '14 at 18:11
  • The thing is I need to create errors for things like MissingToken and TokenNotFound etc etc – tommyd456 Dec 03 '14 at 18:14
  • If you want to set status code for every other error, you have to do it manually and delegate that error as per workflow i mentioned. We are using 500 status code for such errors. – Palak Bhansali Dec 03 '14 at 18:37
3

You should create your own Error type that allows you to provide all the information necessary to act on the error.

var util = require('util');

function HttpError(message, statusCode){
    this.message = message;
    this.statusCode = statusCode;
    this.stack = (new Error()).stack;
}

util.inherits(Error, HttpError);
module.exports = HttpError;

Then include your new error object in your code and use it like

next(new HttpError('Not Found', 404));

Or you could go crazy and implement an error type for each response code pre-populating the statusCode part.

Ref: What's a good way to extend Error in JavaScript?

Community
  • 1
  • 1
tkone
  • 22,092
  • 5
  • 54
  • 78
  • You can omit the `this.stack` part if you don't need the stack trace, but it's super helpful sometimes – tkone Dec 03 '14 at 14:31