In express applications, what is the right way to send error messages to views ?
(we assume that the code is synchronous)
Example 1 :
// Route
Router.route('/')
.get(controller.getIndex);
// Controller
Controller.getIndex = function (req, res, next) {
doSomething(function (err, datas) {
if (err) { res.locals.err = 'error message'; }
// ...
});
res.render(/* view */);
};
// View
<p class="error">${ out.global.err }</p>
Here no problem : if there is an error, I store a message in the response and display it in the view.
Example 2 :
// Route (with multiple middlewares)
Router.route('/')
.get(firstMiddleware, otherMiddleware/*, otherMiddleware2, etc */, controller.getIndex);
// firstMiddleware (always need to be called)
firstMiddleware = function (req, res, next) {
doAlsoSomething(function (err, datas) {
if (err) { res.locals.err = 'error message'; }
// ...
});
next();
};
// otherMiddleware, otherMiddleware2 (need to be called only if no errors)
otherMiddleware = function (req, res, next) {
next();
};
// Controller (need to be called only if want to display the view)
Controller.getIndex = function (req, res, next) {
doSomething(function (err, datas) {
if (err) { res.locals.err = 'error message'; }
// ...
});
res.render(/* view */);
};
// View
<p class="error">${ out.global.err }</p>
In this example, otherMiddleware will be always called. It is not what I want, it should stop the middlewares cycle in case of errors. Then if errors need to be display on the view it should called Controller.getIndex()
with error messages like in example 1. If errors have their own views (as 404, 500...), it should not call the Controller.getIndex()
, but the appropriate view. In any cases, if an error occurs in otherMiddlewareX, the middlewares "after" (otherMiddlewareX + 1, otherMiddlewareX + 2 ... otherMiddlewareN) should not be called.
Anyone can help me to find a "right" way to do that ?
EDIT : similar problem similar stack overflow question
Possible answers (i can give example of implementations if necessary) :
- Put a condition
if (res.locals.err)
in each middleware to jump to the next one in case of errors by callingnext();
. That's not very convenient. - Call an error-handling middleware with
next('error message');
but it is hard to manage every redirection in one function (this is the solution i use) - Use
next('route');
with a route duplication each time to manage error (similar as error-handling middleware solution). - Use
res.redirect();
and flash messages (session, query string, db, cookie...). If I use this solution, I need to make it stateless. I could do it with query string for example, but this is also not very convenient to me. Furthermore, it doesn't really answer the question directly but more the question how to pass message between requests in REST API.
There is probably a way to do that easily with express app, but I can't arrive to figure out what's the right way. Could you please help me ?
Thank you in advance.
EDIT : More details about possible answers (third solution).
With next('error message');
I have an error-handler middleware where I need to display the good view. The view can be a 500, 404, 406... but also a 200 with an error message on it. Firstly, I need to give the status code to this middleware, then if it's a 200 I need to call the view that corresponds to the error. The problem is that I don't always know which view to call. I can have a POST on /auth that needs to be redirected to GET /login. I need to "hardcode" it and can't write the same code for every situations or i need to pass the view/controller in each next('error message');
call. Even the redirection is hard, because sometimes I need to call a controller, but sometimes I needs to go through another middleware cycle by calling the route, not the controller and the only way I found is return app._router.handle(req, res, next);
which looks more as a "hack" that an official solution. If i redirect with res.redirect(); i came back to my second possible answer where i need to pass some flash messages. To finish, this is the solution i use (next(err)
), but i was hoping for a better way.