Home > Net >  Calling `next()` in a route handler
Calling `next()` in a route handler

Time:06-07

Is it valid to call next() in route handler?

In my app I have a middleware at the end of the stack to handle all the unidentified requests.

What I want to do is to send an error page as response when the invalid title is encountered.

The snippet in question is the following:

app.get('/:title', (req, res, next) => {
  const title = req.params.title;

  if (title.isValid()) {
    res.render('post', { title });
  } else {
    next();
  }
});

This is the middleware to handle the unidentified requests:

app.use((req, res, next) => {
  res.status(404).render('error');
  next();
});

FYI: the snippets above do work. I am just not sure if this is the right way to implement this sort of behavior.

CodePudding user response:

You have basically three choices when you want to send an error response.

  1. You can just send the error response right where the error occurs and not call next().

  2. You can call next(err) where you create an appropriate Error object and let Express' error handling process that error and send the response (which could also be your own custom error handler that the error would flow to).

  3. You can call next() and rely on hitting your default 404 error handler (as you show in your question). This will only work if there are no other routes that might also try to handle this request.

There are logical reasons for any of these methods, depending upon your app architecture plan and just how you want to do things. All can work.

Is it valid to call next() in route handler?

Yes, if you want to continue routing to other route handlers or you know there are no more route handlers that will match and you want it to flow to the 404 error handler.

You can use next() equally well from either middleware or a route handler. It behaves no different in either. The main difference between app.use() and app.get() is just in how it matches the route, not in what happens once the middleware/route handler executes on a matching route. They work the same in that regard.

FYI, app.get() is JUST a more specific version of app.use().

  1. app.get() only matches the GET http verb whereas app.use() matches all http verbs.

  2. app.get() requires a full path match, app.use() will match on a partial path match. For example the path /category/mountain will match app.use("/category", ...), but not app.get("/category", ...).

See What is the difference between a route handler and middleware function in ExpressJS? for some further explanation.

Once they've matched are are executing the code in the handler, they work identically with next() or res.send(), etc...

So, it's perfectly fine to use next() in a route handler if your desired architecture wants to do it that way. You do have to make sure you're always sending exactly one http response for an incoming request. Never failing to send a response and never sending more than one response. So, that becomes a requirement of however you choose to do things. For example, you would never call next() AND send a response in that same handler because that would likely lead to sending multiple responses.

There are even cases where you might have two matching routes for the same path and if the first one decides that it shouldn't handle the request (perhaps because of some state or some query parameter or something like that), it can call next() to allow the second one to get a chance to process that request.

  • Related