I'm building out a handler for middleware and I discovered that when you return the route
string as an argument for the next
callback it's value is null
.
Here's the example:
var express = require('express')
var app = express()
app.use('/', function (req, res, next) {
var router = express.Router()
router.use(function (req, res, next) {
return next('route')
})
return router(req, res, function (nextValue) {
console.log('// value of next')
console.log(nextValue)
return next(nextValue)
})
})
app.use('/', function (req, res, next) {
return res.send('hi')
})
module.exports = app
Which means you can't just pass the next handler in like this:
app.use('/', function (req, res, next) {
var router = express.Router()
router.use(function (req, res, next) {
return next('route')
})
return router(req, res, next)
})
I know this looks very redundant because you can just do this:
app.use('/', function (req, res, next) {
return next('route')
})
However I am building a library that needs to use nested middleware in this fashion. It seems that my only option is to use a different string because If I do this:
router.use(function (req, res, next) {
return next('anystring')
})
The next
callback does provide nextValue
with anystring
.
Why does the string route
not propagate through nested middleware?
This seems like it actually makes sense for express to not return route
because at that point route that route is finished.
First off .use
doesn't support next('route')
. So I used .all
instead. Even that doesn't return the string "route". So I needed to inject some middleware into the router at the end. If the value of nextRoute
is not updated, then next('route')
was called sometime during the middleware stack and I can propagate it upward to the parent middleware.
I found that I'd have to inject a piece of middleware into the end to
app.use(function (req, res, next) {
var router = express.Router()
var nextRoute = true
router.all('/', [
function (req, res, next) {
return next('route')
},
function (req, res, next) {
nextRoute = false
return res.send('hi')
},
])
return router(req, res, function (nextValue) {
if (nextRoute && !nextValue) return next('route')
return next(nextValue)
})
})
app.use('/', function (req, res, next) {
return res.send('hi')
})
This allows for my middleware-nest
module to work:
var _ = require('lodash')
var express = require('express')
/** Allow for middleware to run from within middleware. */
function main (req, res, next, Router, middleware) {
var args = _.values(arguments)
middleware = _.flatten([_.slice(args, 4)])
Router = (Router) ? Router : express.Router
var router = Router()
var nextRoute = true
middleware.push(function (req, res, next) {
nextRoute = false
return next()
})
router.all('*', middleware)
return router(req, res, function (nextValue) {
if (nextRoute && !nextValue) return next('route')
return next(nextValue)
})
}
main.applyRouter = function (Router) {
Router = (Router) ? Router : express.Router
return function () {
var args = _.values(arguments)
args.splice(3, 0, Router)
return main.apply(null, args)
}
}
module.exports = main