I am creating an API with NodeJS, Express and PassportJS but I think this is a JavaScript question.
app.get('/test', function (req, res, next) {
passport.authenticate('bearer', { session: false },
function (err, user, info) {
if (user === false) {
res.send('ko');
} else {
res.send('ok');
}
})(req, res, next);
});
My question is:
Why is (req, res, next) after the authenticate function? Is it related with the scope?
Seems that the function password.authenticate returns a function/closure. The code is like
foo(x, y)(z);
i.e. the function returned by the call foo(x, y) is called with parameter z.
A very simple example is
function multiplier(k) {
return function(x) { return x*k; };
}
console.log(multiplier(7)(6)); // outputs 42
The () call the function. The variables inside it are passed to it as arguments. You can see them coming into the containing function on line one of your code.
Related
I use passport.js to authenticate user. I have 2 function there to check whether user is logged in or not.
First function:
isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
else {
res.redirect('/');
}
}
2nd function:
isLoggedInCheck(req, res) {
if (req.isAuthenticated()) {
return true;
}
else {
return false;
}
}
I take these 2 functions in class called Helper.
When I use the 1st function (I pass it in routes function as middleware) it works:
var Helper = require('../helpers/helper');
var helper = new Helper();
router.get('/', helper.isLoggedIn, admin.melihat_daftar_venue);
But when i want to use second function:
if (helper.isLoggedInCheck) {
//code
}
else{
}
The function just return function definition instead of true/false. How to fix it. Thanks
You are using isLoggedIn as a ExpressJS middleware while isLoggedInCheck inside condition that's why you need to call function( helper.isLoggedInCheck(req, res) inside if condition while define inside get function
if (helper.isLoggedInCheck(req, res)) {
//code
}
else{
}
and first one is
router.get('/', helper.isLoggedIn, admin.melihat_daftar_venue);
or (not recommended, just showing example)
router.get('/', (req, res, next) => {
helper.isLoggedIn(req, res, next)
}, admin.melihat_daftar_venue);
exports.signin = function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err || !user) {
res.status(400).send(info);
} else {
// Remove sensitive data before user.password = undefined; user.salt = undefined;
req.login(user, function(err) {
if (err) {
res.status(400).send(err);
} else {
res.json(user);
}
});
}
})(req, res, next);
};
This a piece of code in the "MEAN Web Development" book by AmosQ.Haviv.Who could tell me what the method passport.authenticate()'tail:(req, res, next) means?Is that a Closure?
passport.authenticate() will probably take in the settings 'local' (a domain ? ) and the calllback to create a new function that will do the authentication.
This function will indeed create a closure over 'local' and the callback.
The new auth function will expect 3 parameters: the original req(uest), res(ponse) object and a next parameter and is immediately called using the ( req, res, next ) syntax.
So it's very likely that this specific function will do the login and then run the callback used to create the auth function, passing req and res back into the callback.
Look at it as a way to use the passport.authenticate() method to create different versions of logins you can use. One for 'local', one for 'otherDomain', etc.
I have a router handler configured in a Restify route. In that handler I make a call to a custom module where I do some error checking. When I hit an error condition, I my code returns next(err). I see the error message in the browser, but for some reason my code continues executing after that as well.
The Restify router handler
HttpHandlers.prototype.callHttp = function(req, res, next) {
myUtils.checkInputRules(req, res, next, handlerConfig.inputRules);
//This code is getting executed:
logger.debug("Updated ...
The function being called:
myUtils.checkInputRules = function checkInputRule(req, res, next, inputRules) {
...
} else {
if (inputRule.ifFalse) {
var evalStr = inputRule.ifFalse;
if (evalStr != null) {
logger.debug("Executing condition.iFalse: "+evalStr);
//The code is itting this location
return next(new Error("Internal Error: Failure."));
...
You didn't include the entire code but the issue may be something like this: When you return from a function, it is important which function you return from. For example:
function handler(req, res, next) {
helper(req, res, next);
// this will still run
}
function helper(req, res, next) {
if (something) return next();
}
Here it seems that you are running the myUtils.checkInputRules function and you are returning from your myUtils.checkInputRules function, but you are not actually returning from HttpHandlers.prototype.callHttp so everything after myUtils.checkInputRules(req, res, next, handlerConfig.inputRules); is still executed.
You didn't show the entire code but it seems all synchronous. In that case you can do something like this:
function handler(req, res, next) {
if (helper(req, res, next)) {
// next() was already called
} else {
// do something else - next() not called yet...
}
}
function helper(req, res, next) {
if (something) {
next();
// indicate that next() was already called:
return true;
}
// possibly do something else
}
I am using Express.js as http server. Defined all my routes.
Most endpoints need to verify session before returning a response. E.g. below code serves users in the system and list of services respectively:
function getUsers(req, res, next) {
verifyUser(req, res, next, function () {
//serve users
});
}
function getServices(req, res, next) {
verifyUser(req, res, next, function () {
//serve services
});
}
You probably noticed there is a verifyUser function which validates the session. Which is as below.
function verifyUser(req, res, next, callback) {
var sessionKey = req.cookies.sessionKey;
var user = users.userBySession(sessionKey);
if (user) {
callback(req, res, next, user);
} else {
res.status(401).send({
message: 'Unauthorized'
});
}
}
As you can see I keep passing in req, res and next parameters along with a callback whenever I use this function.
I tried to use apply function to make it easier. Changed my getUsers function like this:
function getUsers(req, res, next) {
verifyUser
.apply(null, arguments, function () {
//serve users
});
}
The problem with this approach is callback is not passed into verifyUser function. And I don't really like passing null as scope with each call.
How can I achieve this by writing less and better code ? Any ideas?
You could use bind to create a 'partial function':
// create bound responseHelper object
var responseHelper = verifyUser.bind(null, req, res, next);
// usage
responseHelper(getUsersCallback); // same as verifyUser(req, res, next, getusersCallBack);
I think you're looking to turn verifyUser into a middleware function.
function verifyUser (req, res, next) {
var user = // yadda yadda session stuff
if (user) {
req.user = user; // [1] what you do to the req object here...
} else {
return res.status(401).send({ message: "No way Smokey Joe"});
/**
* alternatively, do something like
* var err = new Error("Not authorized");
* err.statusCode = 401;
* return next(err);
*
* this will kick off Express' error handling mechanism,
* which you should read about in the docs (see the link below)
*/
}
next();
// very important to call next after this verifyUser has done its job
// if you don't, the next middleware won't go off,
// and the request will just hang
}
function getUsers (req, res, next) {
// [2] will show up on the req object here, assuming you chain these
// two functions together as middleware
}
app.get("/users", verifyUser, getUsers);
app.get("/services", verifyUser, getServices);
// here's a route that needs no session auth, so no need to verifyUser
app.get("/latest-posts", getLatestPosts);
When you tell Express to use a function or attach a function to a route path via get('/my/route', hanlderFun) or some such, you've basically turned handlerFun into a middleware.
You can define however many middleware as handlers on a route as you like, and they'll all execute in turn as long as you keep calling next.
app.post("/checkout", verifyUser, tallyCart, checkInventory, doPayment, sendInvoice);
The job of next is to pass control from the current middelware to the next one. It's an object
You can do other stuff with next, too, which you should read up on in the docs.
http://expressjs.com/en/guide/writing-middleware.html
http://expressjs.com/en/guide/using-middleware.html
The docs on routing have good info on middleware as well:
http://expressjs.com/en/guide/routing.html
For extra credit, check out error handling middleware, too:
http://expressjs.com/en/guide/error-handling.html
I'm trying to avoid callback hell by breaking down my Express / Kraken.js controller into smaller callback functions.
I was processing a request and had about 6 levels of nested anonymous callback functions.
so now I have my main function that looks like this:
// ugh, I know this isn't right
var globalProducts = {};
module.exports = function (server) {
server.get('/project', function (req, res) {
var data = req.query;
globalData = data;
if(!data.projectId || !data.ruleSetId)
res.json({error: "Incomplete input data."});
// pass response to products call back
Project.findOne({ _id: mongoose.Types.ObjectId(data.projectId) }, setUpProducts);
});
};
function setUpProducts(err, project){
// get all products and pass them down the pipe
project.findAllChildren(setUpRules);
}
function setUpRules(err, products) {
// we need to access products in another function
globalProducts = products;
// find the rule set and build the rule Flow
RuleSet.findOne({ _id: mongoose.Types.ObjectId(globalData.ruleSetId) }, function(err, ruleSet) {
ruleSet.buildFlow(processFlow);
});
}
My question is what is the best way to pass around info between callbacks ? My solution was var globalProducts = {}; but to me, the controller contain any 'global state' .. whats the best way to handle this ?
Doing this is a bad idea. It will cause race condition type issue — basically it's the same as sharing data in multithreaded environment. Instead you can use req or res to store data. To do that you need them in scope, so you can define all functions inside route handler or make each function a middleware so it will have req and res as arguments. Here is an example of this approach:
function check (req, res, next) {
if(!req.query.projectId || !req.query.ruleSetId) return res.json({error: "Incomplete input data."});
next()
}
function findProject (req, res, next) {
Project.findOne({ _id: mongoose.Types.ObjectId(req.query.projectId) }, after);
function after (err, project) {
if (err) return next(err);
req.project = project;
next();
}
}
function findProducts (req, res, next) {
req.project.findAllChildren(after)
function after (err, products) {
if (err) return next(err);
req.products = products;
next();
}
}
function respond (req, res) {
res.render('view', {
products : req.products,
project : req.project
});
}
module.exports = function (server) {
server.get('/project', check, findProject, findProducts, respond);
};