How return statement work in nodes - node.js

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.

Related

Conditionally serve React static files with Node (express.static)

app.use(function (req) {
if (myCondition(req)) {
express.static(`${__dirname}/REACT_APP_1`);
} else {
express.static(`${__dirname}/REACT_APP_2`);
}
});
Trying to serve different builds depending on the condition but it does not seems to be working as expected, I have already searched but nothing seems to be matching my condition, is there anything I'm doing wrong?
express.static() returns a middleware function. That middleware function has to get called while processing a specific route in order to actually do something useful. You were creating the middleware function, but never actually calling it so you never saw any results.
You could fix that like this:
// create our two express.static() middleware handlers
const handler1 = express.static(`${__dirname}/REACT_APP_1`);
const handler2 = express.static(`${__dirname}/REACT_APP_2`);
app.use(function (req, res, next) {
if (myCondition(req)) {
handler1(req, res, next);
} else {
handler2(req, res, next);
}
});
Note, I pulled the creation of the two express.static() handlers out of the app.use() body because there is no need to create them over and over inside of app.use(). You can create each of them once and then just use the appropriate one according to your conditional by calling it and passing it the (req, res, next) arguments for the current request.

Middleware hangs

I have the following middleware that does nothing but call next():
export default function (options) {
return function (req, res, next) {
next()
};
}
I'm trying to use it like this:
import mymiddleware from '../middlewares/mymiddleware';
router.post('/', mymiddleware, function(req, res, next) {
res.status(200).send()
});
When I post to the route it just hangs. I would expect this to return just return a 200 OK (which it does if I remove mymiddleware from my route)
You are exporting a function that returns a middleware function when it is called. You have to call that outer function to get the middleware function. You are not calling it.
So, you're passing a function as middleware that just returns another function which is never called so thus it never calls next() and thus your route appears to just get stuck.
You can fix it in two ways. First, you can change your export to just export a straight middleware function:
export default function (req, res, next) {
next()
}
Or, secondly if you need to keep the nested architecture so you can pass it options when using it, you have to actually call it and pass the required options to it:
import mymiddleware from '../middlewares/mymiddleware';
router.post('/', mymiddleware(someOptions), function(req, res, next) {
res.status(200).send()
});

Node.js Express - next() callbacks

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();
}
);

Express next function, what is it really for?

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();
})

what is "next()" in nodejs (expressjs)? [duplicate]

I see a lot of use next in node.js.
What is it, where does it come from? What does it do? Can I use it client side?
Sorry it's used for example here:
http://dailyjs.com/2010/12/06/node-tutorial-5/
look for the loadUser function.
This appears to be a variable naming convention in Node.js control-flow code, where a reference to the next function to execute is given to a callback for it to kick-off when it's done.
See, for example, the code samples here:
http://blog.mixu.net/2011/02/02/essential-node-js-patterns-and-snippets/
Let's look at the example you posted:
function loadUser(req, res, next) {
if (req.session.user_id) {
User.findById(req.session.user_id, function(user) {
if (user) {
req.currentUser = user;
return next();
} else {
res.redirect('/sessions/new');
}
});
} else {
res.redirect('/sessions/new');
}
}
app.get('/documents.:format?', loadUser, function(req, res) {
// ...
});
The loadUser function expects a function in its third argument, which is bound to the name next. This is a normal function parameter. It holds a reference to the next action to perform and is called once loadUser is done (unless a user could not be found).
There's nothing special about the name next in this example; we could have named it anything.
It is naming convention used when passing callbacks in situations that require serial execution of actions, e.g. scan directory -> read file data -> do something with data. This is in preference to deeply nesting the callbacks. The first three sections of the following article on Tim Caswell's HowToNode blog give a good overview of this:
http://howtonode.org/control-flow
Also see the Sequential Actions section of the second part of that posting:
http://howtonode.org/control-flow-part-ii
It's basically like a callback that express.js use after a certain part of the code is executed and done, you can use it to make sure that part of code is done and what you wanna do next thing, but always be mindful you only can do one res.send in your each REST block...
So you can do something like this as a simple next() example:
app.get("/", (req, res, next) => {
console.log("req:", req, "res:", res);
res.send(["data": "whatever"]);
next();
},(req, res) =>
console.log("it's all done!");
);
It's also very useful when you'd like to have a middleware in your app...
To load the middleware function, call app.use(), specifying the
middleware function. For example, the following code loads the
myLogger middleware function before the route to the root path (/).
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);

Resources