Stronglooop loopback after remotehook couldn't modify response - javascript

I want to added extra details on login request and I have the following
module.exports = function(UserAccount) {
UserAccount.afterRemote('login', function(ctx, result, next) {
var response = [];
if (ctx.result) {
var userId = result.userId;
var token = result.id;
// attach user profile
UserAccount.findById(userId, function(err, user) {
if (err)
console.log(err);
if (user) {
response.profile = user;
response.accessToken = token;
ctx.result = response;
console.log(ctx.result);
return next();
}
});
}
});
};
the log just before the next() callback call logs correctly.
The problem is that is always returns empty response .
What is the problem ?

Just call next() instead of returning it. Also, modify ctx.res.body to modify the actual response body.

Related

What would be necessary to code the callback function to receive the access token?

I am trying to retrieve the access token from an API (https://github.com/Axosoft/node-axosoft/)
To receive an access token we have to follow this process:
var axo = nodeAxosoft(axosoftUrl, credentials);
axo.Api.getLoginUrl(function(url) {
// open browser using authorizationUrl and get code parameter from
//redirected Url after login
var code = 'code received from redirect';
axo.Api.exchangeCodeForToken(code);
});
As I did not understood exactly how to get the code following that example nor what is the url parameter on getLoginUrl, I did it on my own.
I have a login route that redirects the user to the axosoft website for authentication and redirects the user to the /authorization-process route on my application.
On the /authorization-process I get the code returned by the login and call a function that should get the access token by calling:
axo.Api.exchangeCodeForToken(code);
Code:
var axosoft_code = req.query.code;
console.log(axosoft_code);
var token = request.exchangeAuthCodeForAccessToken(axosoft_code)
.then(function(token)
{
res.send(token);
})
The Method:
var connection = nodeAxosoft(client_url, credentials);
return new Promise(function(resolve, reject){
console.log("CODE: ", axosoft_code)
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(token){
console.log(token);
resolve(token)
})
The problem is that returns null
I had a look at the API lib api.js and found that:
https://github.com/Axosoft/node-axosoft/blob/master/lib/api.js
function exchangeCodeForToken(code, callback) {
_credentials.code = code;
_access_token = '';
_authenticateCredentails(function (err) {
if (!err) {
callback(null, _access_token);
} else {
callback(err);
}
})
}
So I have two questions:
Does anyone has an Idea what am I doing wrong?
What would be necessary to code the callback function?
The method expects a callback function but I don't really know how to do it.
EDIT:
return new Promise(function(resolve, reject){
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(response,err){
if(!err){
console.log("token",response)
resolve(token);
}
else{
console.log("error",err)
resolve(token);
}
});
})
OR
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(response,err){
if(!err){
console.log("token",response.body)
return response.body;
}
else{
console.log("error",err)
return err;
}
});
I am giving to my callback function two args (response and err), my problem is that I am falling at the else condition.
The output of err is something similar to a token though the documentation here shows that it should be like that:
{
"error" : "invalid_request",
"error_description" : "One or more parameters are missing: client_secret"
}
Another point is that the page is frozen waiting for something to happen but nothing happens.
Given that this is the input:
function exchangeCodeForToken(code, callback) {
_credentials.code = code;
_access_token = '';
_authenticateCredentails(function (err) {
if (!err) {
callback(null, _access_token);
} else {
callback(err);
}
})
}
You should format your call as:
exchangeCodeForToken(axosoft_code, function(err, response) {
if (err) {
// Deal with error
} else {
// Deal with response
}
}
Node functions often pass through error variables first so that you have to receive them, which is considered good practice.

method in express js get() - returns undefined

I have this Node.js code that should, using Express.js http get, decode my jwt token from my http auth header.
When I write the code of decodeToken() inside of my express js get() method, everything works fine.
When I extract it to outside method (decodeToken() method) I get that undefined value from this method. Mind you, when this code was hard coded inside of the method get() it works.
Why is that, the async nature of Node.js? Does the method finish after the get() method was supposed to assign the token?
If I will use promises, will it solve that?
var jwtCheck = expressJwt({
secret: "some secret"
});
app.use('/test', jwtCheck);
app.get('/test', function (req, res) {
var token = req.get('Authorization').split("Bearer ")[1];
var information = decodeToken(token)
console.log("information: "+information);
if (information!=null) {
res.json(information);
}
else {
res.json('Failed to authenticate token.');
}
});
var decodeToken = function (token) {
console.log(token);
jwt.verify(token, secret, function (err, decoded) {
if (err) {
console.log('Failed to authenticate token.');
return null;
} else {
return (decoded);
}
});
}
var getToken = function (req) {
return req.get('Authorization').split("Bearer ")[1];
}
jwt.verify is async because you pass a callback to it so anything that calls it needs to handle that. You could look at promises to clean up the logic a little bit but just using the code you have you could modify it like this:
var jwtCheck = expressJwt({
secret: "some secret"
});
app.use('/test', jwtCheck);
app.get('/test', function (req, res) {
var token = req.get('Authorization').split("Bearer ")[1];
// pass callback to decodeToken that gets called after the token is verified
decodeToken(token, function(information) {
// this function won't execute until decodeToke calls it as `next()`
console.log("information: "+information);
if (information!=null) {
res.json(information);
}
else {
res.json('Failed to authenticate token.');
}
})
});
// accept `next` callback
var decodeToken = function (token, next) {
console.log(token);
jwt.verify(token, secret, function (err, decoded) {
if (err) {
console.log('Failed to authenticate token.');
return next(null);
} else {
return next(decoded);
}
});
}
var getToken = function (req) {
return req.get('Authorization').split("Bearer ")[1];
}

How to wait mongoose .exec function to be done?

I am some cofused by asychronous nodejs and mongoose. Simplily, I want to post an array of usernames and check, if a username is in database, then I put it in the valid array, otherwise, put it in the invalid array.
Here is my current code:
var User = require('../../db/models/user');
api.post('/userlist', function(req, res) {
var invalid = []; // usernames which can not be found in database
var valid = []; // usernames which can be found in database
(req.body.userlist).forEach(function(username) {
User
.findOne({username: username})
.exec(function(err, user) {
if (err) {
res.send(err);
return;
} else if (!user) {
invalid.push(username);
} else {
valid.push(req.params.item);
}
});
});
res.send({
Invalid: invalid,
Valid: valid
});
});
When I executed the above code, it outputs the intial empty array directly.
Invalid: [],
Valid: []
I know it is because nodejs first execute this res.send then execute function .exec(function(err, user), but i do not know how to get the right invalid and valid array, pls advise.
Your best bet is to use a promise:
api.post('/userlist', (req, res) => {
// Takes a username and returns a promise for information on that username.
function findByUsername(username) {
return new Promise((resolve, reject) =>
User.findOne({username}).exec((err, user) =>
err ? reject(err) : resolve(user)
)
);
}
// Iterate the array and transform each user to a promise for data on that user.
Promise.all(req.body.userlist.map(findByUsername))
// Then, when all of the promises in that new array resolve
.then(allUserDataInOrder => {
// Find all the valid ones (if (user))
let Valid = allUserDataInOrder.filter(Boolean); // Only those who are truthy
// And all the invalid ones (if (!user))
let Invalid = allUserDataInOrder.filter(userData => !userData); // Sadly, no convenient function here :(
// And send both away
res.send({Valid, Invalid}); // Short syntax FTW!
})
.catch(res.send); // Called with error object if any.
});
While these other solutions solve what you're trying to accomplish, they still incorporate bad design by iterating findOne(). Executing 1 query for every item in your list is incredibly inefficient. Using an $in query and a basic map, you can use a single query:
var User = require('../../db/models/user');
api.post('/userlist', function(req, res) {
User.find({username: {$in: req.body.userlist}}, function(err, users) {
if (err) {
return res.send(err);
}
// create a map of all the users in your list that exist in your database
var dbUserMap = {};
users.forEach(function(user) {
dbUserMap[user.username] = true;
});
var valid = [];
var invalid = [];
// check your POST list against the database map
req.body.userlist.forEach(function(username){
if (dbUserMap[username]) {
valid.push(username);
}
else {
invalid.push(username);
}
});
res.send({
valid: valid,
invalid: invalid
});
});
});
Try to use async module:
var invalid = [];
var valid = [];
async.each(req.body.userlist, function(name, next) {
User.findOne({username: name}, function(err, user) {
if (err) {
return next(err);
}
if (!user) {
invalid.push(name);
} else {
valid.push(name);
}
next();
)};
}, function(err) {
if (err) {
return res.send(err);
}
res.send({
Invalid: invalid,
Valid: valid
});
});

Cannot return values to response with mongoose/mongodb and nodejs

I am using Nodejs, ExpressJs, MongoDB via Mongoose. I have created a simple UserSchema . I have my code separated into multiple files because I foresee them getting complex.
The url '/api/users' is configured to call the list function in 'routes/user.js' which happens as expected. The list function of UserSchema does get called, but it fails to return anything to the calling function and hence no result goes out.
What am I doing wrong ?
I tried to model it based on http://pixelhandler.com/blog/2012/02/09/develop-a-restful-api-using-node-js-with-express-and-mongoose/
I think I am doing something wrong with the function definition of userSchema.statics.list
app.js
users_module = require('./custom_modules/users.js'); // I have separated the actual DB code into another file
mongoose.connect('mongodb:// ******************');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback() {
users_module.init_users();
});
app.get('/api/users', user.list);
custom_modules/users.js
function init_users() {
userSchema = mongoose.Schema({
usernamename: String,
hash: String,
});
userSchema.statics.list = function () {
this.find(function (err, users) {
if (!err) {
console.log("Got some data"); // this gets printed
return users; // the result remains the same if I replace this with return "hello"
} else {
return console.log(err);
}
});
}
UserModel = mongoose.model('User', userSchema);
} // end of init_users
exports.init_users = init_users;
routes/user.js
exports.list = function (req, res) {
UserModel.list(function (users) {
// this code never gets executed
console.log("Yay ");
return res.json(users);
});
}
Actually in your code you are passing a callback, which is never handled in function userSchema.statics.list
You can try the following code:
userSchema.statics.list = function (calbck) {
this.find(function (err, users) {
if (!err) {
calbck(null, users); // this is firing the call back and first parameter should be always error object (according to guidelines). Here no error, so pass null (we can't skip)
} else {
return calbck(err, null); //here no result. But error object. (Here second parameter is optional if skipped by default it will be undefined in callback function)
}
});
}
Accordingly, you should change the callback which is passed to this function. i.e.
exports.list = function (req, res){
UserModel.list(function(err, users) {
if(err) {return console.log(err);}
return res.json(users);
});
}

Node.js - howto block around async call. Or non-blocking xmltojs lib

I'm over my head at the moment.
I'm new to node and writing a passportjs module for Freshbooks. There's a Passport function I'm trying to implement that get's a user's profile.
This code uses Passport's OAuth foo to make a request.
this._oauth.post(url, token, tokenSecret, post_body, post_content_type, function (err, body, res) {
if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }
try {
var parser = require('xml2json');
var json = parser.toJson(body); //returns a string containing the JSON structure by default
var util = require('util');
console.log(util.inspect(json));
var profile = { provider: 'freshbooks' };
profile.id = json.response.staff.staff_id;
profile.displayName = json.response.staff.first_name + ' ' + json.response.staff.last_name;
profile.name = { familyName: json.response.staff.last_name,
givenName: json.response.staff.first_name };
if (json.response.staff.email) { profile.emails = [{ value: json.response.staff.email }]; }
profile._raw = body;
profile._json = json;
console.log(util.inspect(json));
done(null, profile);
} catch(e) {
done(e);
}
});
I get a response. It's xml. I'm converting it to JSON, but I don't want that actually. I want a plain-old javascript object.
I looked at https://github.com/Leonidas-from-XIV/node-xml2js but the examples don't show how to get the result out.
var parseString = require('xml2js').parseString;
var xml = "<root>Hello xml2js!</root>"
parseString(xml, function (err, result) {
console.dir(result);
});
What do I do to block around this code till the call is complete and get result out? I'm not sure how to merge these two callbacks together.
you can ask xml2json to return object:
var json = parser.toJson(body, {object: true});
if you decide to use async parser then just put your done callback inside json result handler. There is no need to "block" async function:
var parseString = require('xml2js').parseString;
parseString(body, function(err, json) {
// handle error: return done(err)
// do your logic if no error
// ...
// profile._json = json;
// ...
//
// 'return' result
done(null, profile);
});

Categories

Resources