Express next function, what is it really for?

node.jsExpress

node.js Problem Overview


Have been trying to find a good description of what the next() method does. In the Express documentation it says that next('route') can be used to jump to that route and skip all routes in between, but sometimes next is called without arguments. Anybody knows of a good tutorial etc that describes the next function?

node.js Solutions


Solution 1 - node.js

next() with no arguments says "just kidding, I don't 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 here's 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 doesn't find one then ignore this route handler and check for other ones.

So next() with no arguments allows to pretend you didn't 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() {
  //...
});

Solution 2 - node.js

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 image description here

The router is special, it's middleware that lets you execute one or more middleware for a certain url. So it's 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!')
})

Solution 3 - node.js

IMHO, the accepted answer to this question is not really accurate. As others have stated, it's 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. That's because you are no longer telling express to run the next handler.

So it doesn't 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? Let's 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 can't know when the first handler's callback has finished. You have to tell it by calling next().

Solution 4 - node.js

next() without parameter invokes the next route handler OR next middleware in framework.

Solution 5 - node.js

Summarizing rightly mentioned answers in one place,

  • next() : move control to next function in same route. case of multiple functions in single route.
  • next('route') :move control to next route by skipping all remaining function in current route.
  • next(err) : move control to error middleware
app.get('/testroute/:id', function (req, res, next) {
  if (req.params.id === '0') next() // Take me to the next function in current route
  else if (req.params.id === '1') next('route') //Take me to next routes/middleware by skipping all other functions in current router  
  else next(new Error('Take me directly to error handler middleware by skipping all other routers/middlewares'))
}, function (req, res, next) {
  // render a regular page
  console.log('Next function in current route')
  res.status(200).send('Next function in current route');
})

// handler for the /testroute/:id path, which renders a special page
app.get('/testroute/:id', function (req, res, next) {
  console.log('Next routes/middleware by skipping all other functions in current router')
  res.status(200).send('Next routes/middleware by skipping all other functions in current router');
}) 
//error middleware
app.use(function (err, req, res, next) {
  console.log('take me to next routes/middleware by skipping all other functions in current router')
  res.status(err.status || 500).send(err.message);
});

Solution 6 - node.js

Question also asked about use of next('route') which seems to be covered week in provided answers so far:

  1. USAGE OF next():

In short: next middleware function.

Extract from this official https://expressjs.com/en/guide/writing-middleware.html">Express JS documentation - 'writing-middleware' page:

"The middleware function myLogger simply prints a message, then passes on the request to the next middleware function in the stack by calling the next() function."

var express = require('express')
var app = express()

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

app.use(myLogger)

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)

https://expressjs.com/en/guide/using-middleware.html">This page of Express JS documentation states "If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging."

  1. USAGE OF next('route') :

In short: next route (vs. next middleware function in case of next() )

Extract from this https://expressjs.com/en/guide/using-middleware.html"> Express JS documentation - 'using-middleware' page:

"To skip the rest of the middleware functions from a router middleware stack, call next('route') to pass control to the next route. NOTE: next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.

This example shows a middleware sub-stack that handles GET requests to the /user/:id path."

app.get('/user/:id', function (req, res, next) {
  // if the user ID is 0, skip to the next route
  if (req.params.id === '0') next('route')
  // otherwise pass the control to the next middleware function in this stack
  else next()
}, function (req, res, next) {
  // render a regular page
  res.render('regular')
})

// handler for the /user/:id path, which renders a special page
app.get('/user/:id', function (req, res, next) {
  res.render('special')
})

Solution 7 - node.js

Its simply means pass control to the next handler.

Cheers

Solution 8 - node.js

Notice the call above to next(). Calling this function invokes the next middleware function in the app. The next() function is not a part of the Node.js or Express API, but is the third argument that is passed to the middleware function. The next() function could be named anything, but by convention, it is always named “next”. To avoid confusion, always use this convention.

Solution 9 - node.js

next() is the callback argument to the middleware function with req, and res being the http request and response arguments to next in the below code.

app.get('/', (req, res, next) => { next() });

So next() calls the passed in middleware function. If current middleware function does not end the request-response cycle, it should call next(), else the request will be left hanging and will timeout.

next() fn needs to be called within each middleware function when multiple middleware functions are passed to app.use or app.METHOD, else the next middleware function won’t be called (incase more than 1 middleware functions are passed). To skip calling the remaining middleware functions, call next(‘route’) within the middleware function after which no other middleware functions should be called. In the below code, fn1 will be called and fn2 will also be called, since next() is called within fn1. However, fn3 won’t be called, since next(‘route’) is called within fn2.

app.get('/fetch', function fn1(req, res, next)  {
console.log("First middleware function called"); 
    next();
}, 
function fn2(req, res, next) {
    console.log("Second middleware function called"); 
    next("route");
}, 
function fn3(req, res, next) {
    console.log("Third middleware function will not be called"); 
    next();
})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndreas SelenwallView Question on Stackoverflow
Solution 1 - node.jsAlex WayneView Answer on Stackoverflow
Solution 2 - node.jsPickelsView Answer on Stackoverflow
Solution 3 - node.jsd512View Answer on Stackoverflow
Solution 4 - node.jskyasarView Answer on Stackoverflow
Solution 5 - node.jsArvind DhasmanaView Answer on Stackoverflow
Solution 6 - node.jsUlaView Answer on Stackoverflow
Solution 7 - node.jsGammerView Answer on Stackoverflow
Solution 8 - node.jsHukmaramView Answer on Stackoverflow
Solution 9 - node.jsuser3022150View Answer on Stackoverflow