Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expressjs - Handling Errors With Middleware

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?

like image 868
tommyd456 Avatar asked Dec 03 '14 14:12

tommyd456


People also ask

How does Express middleware handle errors?

Express comes with a default error handler for handling error conditions. This is a default middleware function added by Express at the end of the middleware stack. We call the error handling middleware by passing the error object to the next(error) function.

Does Express support middleware?

Middleware functions are an integral part of an application built with the Express framework (henceforth referred to as Express application). They access the HTTP request and response objects and can either terminate the HTTP request or forward it for further processing to another middleware function.

Is Express Router a middleware?

Note: Router functions are Express middleware, which means that they must either complete (respond to) the request or call the next function in the chain.


2 Answers

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.

like image 169
Palak Bhansali Avatar answered Sep 18 '22 19:09

Palak Bhansali


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?

like image 34
tkone Avatar answered Sep 20 '22 19:09

tkone