node.js – Express next function, what is it really for?

node.js – Express next function, what is it really for?

next() with no arguments says just kidding, I dont actual want to handle this. It goes back in and tries to find the next route that would match.

This is useful, say if you want to have some kind of page manager with url slugs, as well as lots of other things, but heres an example.

app.get(/:pageslug, function(req, res, next){
  var page = db.findPage(req.params.pageslug);
  if (page) {
    res.send(page.body);
  } else {
    next();
  }
});

app.get(/other_routes, function() {
  //...
});

That made up code should check a database for a page with a certain id slug. If it finds one render it! if it doesnt find one then ignore this route handler and check for other ones.

So next() with no arguments allows to pretend you didnt handle the route so that something else can pick it up instead.


Or a hit counter with app.all(*). Which allows you to execute some shared setup code and then move on to other routes to do something more specific.

app.all(*, function(req, res, next){
  myHitCounter.count += 1;
  next();
});

app.get(/other_routes, function() {
  //...
});

In most frameworks you get a request and you want to return a response. Because of the async nature of Node.js you run into problems with nested call backs if you are doing non trivial stuff. To keep this from happening Connect.js (prior to v4.0, Express.js was a layer on top of connect.js) has something that is called middleware which is a function with 2, 3 or 4 parameters.

function (<err>, req, res, next) {}

Your Express.js app is a stack of these functions.

enter

The router is special, its middleware that lets you execute one or more middleware for a certain url. So its a stack inside a stack.

So what does next do? Simple, it tells your app to run the next middleware. But what happens when you pass something to next? Express will abort the current stack and will run all the middleware that has 4 parameters.

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

This middleware is used to process any errors. I like to do the following:

next({ type: database, error: datacenter blew up });

With this error I would probably tell the user something went wrong and log the real error.

function (err, req, res, next) {
   if (err.type === database) {
     res.send(Something went wrong user);
     console.log(err.error);
   }
};

If you picture your Express.js application as a stack you probably will be able to fix a lot of weirdness yourself. For example when you add your Cookie middleware after you router it makes sense that your routes wont have cookies.

Docs

You define error-handling middleware in the same way as other middleware, except with four arguments instead of three; specifically with the signature (err, req, res, next):

app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).send(Something broke!)
})

node.js – Express next function, what is it really for?

IMHO, the accepted answer to this question is not really accurate. As others have stated, its really about controlling when next handler in the chain is run. But I wanted to provide a little more code to make it more concrete. Say you have this simple express app:

var express = require(express);
var app = express();

app.get(/user/:id, function (req, res, next) {
    console.log(before request handler);
    next();
});

app.get(/user/:id, function (req, res, next) {
    console.log(handling request);
    res.sendStatus(200);
    next();
});

app.get(/user/:id, function (req, res, next) {
    console.log(after request handler);
    next();
});

app.listen(3000, function () {
    console.log(Example app listening on port 3000!)
});

If you do

curl http://localhost:3000/user/123

you will see this printed to console:

before request handler
handling request
after request handler

Now if you comment out the call to next() in the middle handler like this:

app.get(/user/:id, function (req, res, next) {
    console.log(handling request);
    res.sendStatus(200);
    //next();
});

You will see this on the console:

before request handler
handling request

Notice that the last handler (the one that prints after request handler) does not run. Thats because you are no longer telling express to run the next handler.

So it doesnt really matter if your main handler (the one that returns 200) was successful or not, if you want the rest of the middlewares to run, you have to call next().

When would this come in handy? Lets say you want to log all requests that came in to some database regardless of whether or not the request succeeded.

app.get(/user/:id, function (req, res, next) {
    try {
       // ...
    }
    catch (ex) {
       // ...
    }
    finally {
       // go to the next handler regardless of what happened in this one
       next();
    }
});

app.get(/user/:id, function (req, res, next) {
    logToDatabase(req);
    next();
});

If you want the second handler to run, you have to call next() in the first handler.

Remember that node is async so it cant know when the first handlers callback has finished. You have to tell it by calling next().

Leave a Reply

Your email address will not be published.