Goowik
Goowik

Reputation: 803

express how to handle errors with redirects & messages

I can't seem to wrap my head around how to properly handle errors.

The basic 404, is no problem (simply set header 404 and render 'not found' page). But let's say for example:

You find a user by id, but the user doesn't exist. I suppose for this you set the header-status to 500. But how do you redirect the page back (or simply assign a redirect page) and set a flashmessage?

In most tutorials I usually find the following:

model.SignUp.forge({id: req.params.id}).fetch({withRelated: ['usermeta']}).then(function(user) {
    res.render('admin/pages/users/details', {title: 'Signups', error: false, details: user});
  }).catch(function(err) {
    res.status(500).json({error: true, data: {message: err.message}});
  });

You simply catch the problem whenever an error occurs. I also come across this sometimes:

transporter.sendMail(mailOptions, function(err) {
    if(err) {
        req.flash('error', 'blablabla');
        res.redirect('back');
    }
});

In the first case you return a json file but no redirect or render. In the second part no status has been provided.

What practices do you guys implement?

Upvotes: 0

Views: 2285

Answers (1)

Paul
Paul

Reputation: 36349

I'm a huge fan of central error handling in my express apps. How does this work? Well, I have a library of HTTP error objects that all have a 'status' property on them. All my route handlers and middeware return a callback with one of those error objects depending on what happened, and do not call res.send (or any other res.* method) if there was an error. I then have an error handling middleware (or more than one, if I it's getting to be complex) that decides if I want to do a redirect or just send the response code, or whatever depending on the needs of the app.

Taking your example:

app.post('/signup', function(req, res, next){
  model.SignUp.forge({id: req.params.id}).fetch({withRelated: ['usermeta']}).then(function(user) {
    res.render('admin/pages/users/details', {title: 'Signups', error: false, details: user});
  }).catch(function(err) {
    return next(new HttpServerError(err)); 
  });
}

an HttpServerError has a status of 500, and so I have at least a 'catch all' error handling middleware that looks like this (in the case of a json api):

app.use(function(err, req, res, next){
  console.log(err.stack);
  res.status(err.status).send({message: err.clientMessage});
});

You can also do multiple handlers, and render or redirect based on the state of the request (e.g. accepts headers or type of error).

For example, in a traditional web app, I might use the name of the error to figure out what template to render, and I might redirect to a login page if it's a 403 error.

For sake of completeness, here's an example HttpServerError:

'use strict';

const util = require('util');

function HttpServerError(message){
  this.message = message;
  this.clientMessage = 'Dangit! Something went wrong on the server!';
  this.status = 500;
  Error.captureStackTrace(this, NotFoundError);
}

util.inherits(HttpServerError, Error);

HttpServerError.prototype.name = 'HttpServerError';

module.exports = HttpServerError;

Upvotes: 2

Related Questions