In Node.js Express - using app.use functions-
why don't I have to do this:
app.use(function(req,res,next){
//do something here
next(req,res);
});
usually I just do this and it works
app.use(function(req,res,next){
//do something here
next();
});
?
next() already knows the req and res for the currently executing request, thus you just call it directly. It is a unique function created just for this request. It also keeps track of where you currently are in the middleware stack such that calling next() executes the next middleware in the chain.
If you look at the express source code for the router, you can actually see the locally defined next() function and can see how it has access to a bunch of closure-defined variables that include req, res and index counter that it uses for advancing through the middleware stack and a bunch of other variables. Thus, it already has access to everything it needs to launch the next middleware call so there is no reason to pass it those things.
FYI, one of the great things about using open source is that you can always just go look at the code yourself and see what it does.
When invoking next(), you have several choices:
You can invoke it as next() and this will just invoke the next middleware handler in the stack.
You can invoke it as next('route') and it will skip to the next route handler.
You can pass an error next(err) and stop all further middleware or router handling except for error handlers.
The details are documented here: http://expressjs.com/guide/error-handling.html.
Here's a note from that page:
next() and next(err) are analogous to Promise.resolve() and
Promise.reject(). They allow you to signal to Express that this
current handler is complete and in what state. next(err) will skip all
remaining handlers in the chain except for those that are set up to
handle errors as described in the next section.
The use of next accepts an optional Error object. if you pass nothing to it, it assumes you're ready to continue onto the next piece of middleware or your actual mounted handler. Otherwise, if you pass an instance of an Error object, you'll bypass your mounted handler (and sequential middleware) and go directly to the error handler.
app.use(function (req, res, next) {
if (!req.user || !req.user.isAuthorized) next(Error('not allowed'))
else next()
})
app.get('/:user', function (req, res, next) {
res.render('users/index', { user: req.user })
})
app.use(function (err, req, res, next) {
console.log(err.message) // not allowed
res.render('500', err)
})
I tried to understand the internal working by looking in the sources provided by jfriend00, but didn't wanted to loose too much time trying to isolate the specific part which handles the callbacks.
So I tried my own:
jsfiddle
function MW(req, res){
var req1 = req, res1 = res;
Array.prototype.shift.apply(arguments);
Array.prototype.shift.apply(arguments);
var MWs = arguments;
console.log(MWs, req1, res1);
function handle(index){
if(index ===MWs.length-1){
return ()=>{MWs[index](req1, res1, ()=>{})};
}
return ()=>{MWs[index](req1, res1, handle(index+1))};
}
var next = handle(0);
next();
}
Basically, it uses recursion to build the chain of callbacks.
You can then use it as Express use/get/post/put/...:
MW(req, res,
(req, res, next)=>{
console.log("first");
req.locals = {
token : 'ok'
};
res.canSend =false;
next();
},
(req, res, next)=>{
console.log("second");
console.log(req.locals.token, res.canSend);
next();
}
);
Related
I am newbie in ExpressJs and I do not clear about return statement of middleware. Please see below code :-
middleware.js
exports.checkPrivilege = (stateName, forPrivilege) => {
return (req, res, next) => { // THIS LINE MAKE CONFUSE, i.e, req, res and next
}
}
module.js
.....
.....
router.post('/create', checkPrivilege('module', 'write'), (req, res, next) => {
});
This means that checkPrivilege() is a function that, when called returns another function. In this case, it returns a function that is of the right format to use as a middleware handler.
So, when checkPrivilege(x,y) is called, it returns another function (that has not been executed yet) that can then be used as middleware.
So, when you see this:
router.post('/create', checkPrivilege('module', 'write'), (req, res, next) => {
// code here
next();
});
This does the following steps:
Creates a POST route handler for the /create route.
Calls checkPrivilege('module', 'write') immediately and as the return value it gets back another function that becomes a middleware handler for the /create route.
Then defines an inline anonymous route handler function for the /create route that will run after the middleware handler is done.
For a bit of clarity, it could also be written:
// create middleware function
let checkPrivilegeMiddleware1 = checkPrivilege('module', 'write');
// create route handler with middleware
router.post('/create', checkPrivilegeMiddleware1, (req, res, next) => {
// code here
next();
});
The typical reason it's done this way is that it is an easy way to make some parameters stateName and forPrivilege available to the middleware without creating another inline function body. This way the checkPrivilege() function can be used in multiple places within your code, each with their own stateName and forPrivilege settings - thus more reusable.
Until now I've defined my get and post handlers with just (req, res) as arguments, with the assumption being that I put these handlers last in the chain of middleware, and make sure that I handle any responses and error handling properly within these handlers... hence it doesn't matter that I don't make any reference to next.
Is this a valid and sensible approach, or is it good practice always to call next() even if (at present) there is nothing coming afterwards? For example, perhaps in the future you might want to do some handling after these routes... or maybe there's a reason I haven't yet come across why it's good practice to always call next().
For example, there is the following simple example in the express routing guide:
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from B!')
})
Of course, I appreciate that this is a very simple example to illustrate that handlers can be chained, and is not intended to provide a complete framework for a get handler, but would it be better to define and use next even in the second handler, as follows?
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res, next) {
res.send('Hello from B!')
next()
})
Or is it actually common practice to assume that a handler function that sends a response back to the client should not call next()... i.e. the assumption should be that the chain will end at the handler that actually sends the response?
Or is there no established practice on this point?
I'm even wondering whether it might be common not to send any response in the get handler but to defer that to a dedicated response handler coming after... by which I mean an OK response handler rather than an error response handler (for which it seems to be common practice to defined a final error handler and call next(err)). So, in a non-error situation, you would call next() and in the following middleware you would do your res.status(200).send(req.mydata) where req.mydata is added in your get handler.
No. You should only call next() if you want something else to handle the request. Usually it's like saying that your route may match that request but you want to act like it didn't. For example you may have two handlers for the same route:
app.get('/test', (req, res, next) => {
if (something) {
return next();
}
// handle request one way (1)
});
app.get('/test', (req, res) => {
// handle request other way (2)
});
Always the first matching handler is called, so for the GET /test request the first handler will be called, but it can choose to pass the control to the second handler, as if the first didn't match the request.
Note that if the second handler doesn't intend to pass the request to the next handler, it doesn't even have next in its arguments.
If there was no second handler, then the standard 404 handler would be used if the first one called next().
If you pass an argument to next() then an error handling middleware will be called.
My rule of thumb is to handle the response in the handler if you're going to give a 20x (Success) response code, and in centralized error handling if not. That looks something like this in practice:
// ./routes/things.js
const express = require('express');
const Thing = require('../models/thing');
const Router = express.Router();
// note, the handlers might get pulled out into a controllers file, if they're getting more complex.
router.param('thingId', (req, res, next, id) => {
Thing.findById(id, (e, thing) => {
if (e) return next(e);
// let's say we have defined a NotFoundError that has 'statusCode' property which equals 404
if (!bot) return next(new NotFoundError(`Thing ${id} not found`));
req.thing = thing;
return next();
});
});
router.get('/', (req, res, next) => {
// possibly pull in some sort, limit, and filter stuff
Thing.find({}, (e, things) => {
if (e) return next(e);
res.send(things);
});
});
router.route('/:thingId')
.get((req, res) => {
// if you get here, you've already got a thing from the param fn
return res.send(req.thing);
})
.put((req, res, next) => {
const { name, description } = req.body; // pull whitelist of changes from body
let thing = req.thing;
thing = Object.assign(thing, { name, description }); // copy new stuff into the old thing
thing.save((e) => {
if (e) return next(e);
return res.send(thing); // return updated thing
});
});
Keeping each logical chunk in its own file can reduce repetition
// ./routes/index.js then mounts the subrouters to the main router
const thingsRoute = require('./things');
const express = require('express');
const router = express.Router();
/* .... other routes **/
router.use('/things', thingsRoute);
Error handling is then centralized, and can be mounted either in its own file or right on the app:
// in ./index.js (main app entry point)
const express = require('express');
// this will require by default ./routes/index.js
const routes = require('./routes');
const app = express();
const log = require('./log');// I prefer debug.js to console.log, and ./log.js is my default config file for it
/* ... other app setup stuff */
app.use(routes);
// you can mount several of these, passing next(e) if you don't handle the error and want the next error handler to do so.
app.use((err, req, res, next) => {
// you can tune log verbosity, this is just an example
if (err.statusCode === 404) {
return res.status(404).send(err.message);
}
log.error(err.message);
log.verbose(err.stack); // don't do stack traces unless log levels are set to verbose
return res.status(500).send(err.message);
});
There are a few posts on this question but none that answers the issue directly, head-on. Let me clarify that I understand (or so I think) the use of next(), next('route'), return next(), return and their impact on control flow.
My entire middleware for the app consists of a series of app.use, as in:
app.use(f1);
app.use(f2);
app.use(f3);
app.use(f4);
...
In each of these middlewares, I have possibility of sending the response and be done without any need for further processing. My problem is that I am unable to stop the processing from going to the next middleware.
I have a clumsy work around. I just set a res.locals.completed flag after sending a response. In all the middlewares, at the very start, I check this flag and skip processing in the middleware if the flag is set. In the very first middleware, this flag is unset.
Surely, there must be a better solution, what is it? I would think that Express implicitly would do this checking and skip the middlewares through some express-specific method?
According to the express documentation on http://expressjs.com/guide/using-middleware.html
If the current middleware does not end the request-response cycle,
it must call next() to pass control to the next middleware,
otherwise the request will be left hanging.
so if a middleware needs to end the request-response early, simply do not call next() but make sure that the middleware really ends the request-response by calling res.end, res.send, res.render or any method that implicitely calls res.end
app.use(function (req, res, next) {
if (/* stop here */) {
res.end();
} else {
next();
}
});
Here is an example server showing that it works
var express = require('express');
var app = express();
var count = 0;
app.use(function(req, res, next) {
console.log('f1');
next();
})
app.use(function(req, res, next) {
console.log('f2');
if (count > 1) {
res.send('Bye');
} else {
next();
}
})
app.use(function(req, res, next) {
console.log('f3');
count++;
next();
})
app.get('/', function (req, res) {
res.send('Hello World: ' + count);
});
var server = app.listen(3000);
you will see the after 3 requests, the server shows "Bye" and f3 is not reached
I would like to use a middleware for checking users credentials only for some routes (those that start with /user/), but to my surprise server.use does not take a route as first argument and with restify-namespace server.use effect is still global.
Is there other way better than passing my auth middleware to all routes alongside the controller?
I think I'm going to just use server.use and inside the middleware make the following route check:
if (req.url.indexOf('/user/') !== 0) {
return next();
}
Unfortunately restify doesn't seem to be like express, which support the * operator. Hence, What I would suggest is grouping the routes that you desire together and apply a .use before them.
That is:
server.get('/test', function(req, res, next) {
// no magic here. server.use hasn't been called yet.
});
server.use(function(req, res, next) {
// do your magic here
if(some condition) {
// magic worked!
next(); // call to move on to the next middleware.
} else {
// crap magic failed return error perhaps?
next(new Error('some error')); // to let the error handler handle it.
}
});
server.get('/admin/', function(req, res, next) {
// magic has to be performed prior to getting here!
});
server.get('/admin/users', function(req, res, next) {
// magic has to be performed prior to getting here!
});
However, I would personally advocate the use of express, but choose whatever fits your need.
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?
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() {
//...
});
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.
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
How do I setup an error handler?
Error Handling
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!')
})
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().
next() without parameter invokes the next route handler OR next middleware in framework.
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);
});
Question also asked about use of next('route') which seems to be covered week in provided answers so far:
USAGE OF next():
In short: next middleware function.
Extract from this official 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)
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."
USAGE OF next('route') :
In short: next route (vs. next middleware function in case of next() )
Extract from this 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')
})
Its simply means pass control to the next handler.
Cheers
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.
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();
})