Automatically logging in a user with KoaJS and PassportJS - javascript

I'm trying to automatically log in a user with PassportJS.
This is my current code:
myRouter.get('/signin', function* (next) {
user = {...};
var res = this.res; // needed for the function below
this.req.login(user, function(err) {
if (err)
console.log('error logging in user - '+err);
return res.redirect('/'); // <--- line 439
});
});
But when I run it, I get the error:
error logging in user - TypeError: undefined is not a function
TypeError: undefined is not a function
at /srv/www/domain.com/app.js:439:32
at /srv/www/domain.com/node_modules/koa-passport/node_modules/passport/lib/http/request.js:49:48
at pass (/srv/www/domain.com/node_modules/koa-passport/node_modules/passport/lib/authenticator.js:293:14)
at Authenticator.serializeUser (/srv/www/domain.com/node_modules/koa-passport/node_modules/passport/lib/authenticator.js:295:5)
at Object.req.login.req.logIn (/srv/www/domain.com/node_modules/koa-passport/node_modules/passport/lib/http/request.js:48:29)
at Object.<anonymous> (/srv/www/domain.com/app.js:434:26)
at GeneratorFunctionPrototype.next (native)
at Object.dispatch (/srv/www/domain.com/node_modules/koa-router/lib/router.js:317:14)
at GeneratorFunctionPrototype.next (native)
at Object.<anonymous> (/srv/www/domain.com/node_modules/koa-common/node_modules/koa-mount/index.js:56:23)

A quick semi-derp moment and I realize to redirect in koa it does not use res but this, you must do the following:
var res = this; // needed for the next function
this.req.login(user, function(err) {
if (err)
console.log('error logging in user - '+err);
return res.redirect('/');
});

Your code is fine, it is just that res is called response, so just change
var res = this.res; in var res = this.response; and it will work fine. res does exist, but it is the Node http module response, not the Koa Response object, and therefore does not have any redirect method. The redirect is aliased to this, which is why you can use this.redirect, but it really is a Response method.
Take a look at http://koajs.com/#context for more details.
To avoid having to assign this, or response, you could just bind this to your function, I think it is cleaner in most cases:
myRouter.get('/signin', function* (next) {
user = {...};
this.req.login(user, function(err) {
if (err)
console.log('error logging in user - '+err);
return this.redirect('/'); // <--- line 439
}.bind(this));
});

Related

where to should write res.send() in node.js app

In my app I have a category collection that saves the category title with its image ID. The image is saved in another collection with its meta data like path , type and so on. So for retrieving category I should retrieve category image in image collection by its ID and add image path to category object that is retrieved from category collection and send it to client...But I don't know where should I send categories to client?
When I send the response face this error :
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:561:11)
at ServerResponse.header (H:\node.js\online-store\app\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (H:\node.js\online-store\app\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (H:\node.js\online-store\app\node_modules\express\lib\response.js:267:15)
at ServerResponse.send (H:\node.js\online-store\app\node_modules\express\lib\response.js:158:21)
at H:\node.js\online-store\app\controllers\pcategory.controller.js:123:19
at H:\node.js\online-store\app\node_modules\mongoose\lib\model.js:4845:18
at processTicksAndRejections (internal/process/task_queues.js:77:11)
Emitted 'error' event on Function instance at:
at H:\node.js\online-store\app\node_modules\mongoose\lib\model.js:4847:15
at processTicksAndRejections (internal/process/task_queues.js:77:11) {
code: 'ERR_HTTP_HEADERS_SENT'
}
This is my code :
exports.getAll = async (req, res) => {
try{
const categories = await ProductCategory.find({});
categories.map(async(category)=>{
await File.findById(category.imageID).exec(function(err,file){
if(err){
console.log(err)
}else if(file) {
category.imagePath = file.file_path;
tempCategories.push(category)
}
res.send(tempCategories);
})
})
return res.send(tempCategories);
}catch {
res.json(err =>{
console.log(err);
res.status(500).send({
message:
err.message || "There is an error in retrieving category"
});
})
}
}
The problem is that nothing in your code is waiting for the asynchronous operations you're doing in your map callback to complete, so it does the res.send at the end right away — and then does res.send again within the map callback later when the async operations complete. Instead, wait for them to finish and send the result.
Also, you're using res.send where I suspect you want res.json, and using res.json later incorrectly (it doesn't take a callback).
See comments:
exports.getAll = async (req, res) => {
try {
// Get the categories
const categories = await ProductCategory.find({});
// Get the files for the categories, wait for the result
const result = await Promise.all(categories.map(async (category) => {
const file = await File.findById(category.imageID).exec();
// You probably can't modify the `category` object, so let's create
// and return a new object
return {...category, imagePath: file.file_path};
}));
// Send the result converted to JSON
return res.json(tempCategories);
} catch (err) { // Accept the error
// Send an error response
res.status(500).json({
message: err.message || "There is an error in retrieving category"
});
}
};
Side note: Your original code was using map without using the array it creates. That's an antipattern (sadly it seems to be one someone somewhere is teaching). I wrote up why and what to do instead here. (In my update to your code, I still use map, but I use the array it creates, passing it to Promise.all so we can wait for all those promises to settle.)
Your Code Like this,
Now Issue is You are sending two times Headers.
You can use like this, Firstly Declare array and push into it what you need and then last of your logic return it or send it.
exports.getAll = async (req, res) => {
try {
const categories = await ProductCategory.find({});
let tempCategories = []; // New Line
await Promise.all(categories.map(async (category) => {
await File.findById(category.imageID).exec(function (err, file) {
if (err) {
console.log(err)
} else if (file) {
category.imagePath = file.file_path;
tempCategories.push(category)
}
});
return category;
}));
res.send(tempCategories);
} catch {
res.json(err => {
console.log(err);
res.status(500).send({
message:
err.message || "There is an error in retrieving category"
});
})
}
}

Return value is always undefined - AWS.SES example running in an Express app

I am using some code from an AWS example to send an email via SES, inside an Express app. The email works great, but I want to be able to change the response to the browser based on the success or failure of sending the email.
But the function that sends the email always returns undefined, I think because the calling function is not awaiting the result properly.
In the express app:
app.post('/api/sendEmail', sendEmail);
async function sendEmail(request, response){
//console.dir(request.body);
await emailer(request.body)
.then(result => console.log(result));
//should base response on result
response.json(('{"status": "success"}'));
}
Then I have another file with the emailer function in it, loaded as emailer.
module.exports = async function sendEmailFunction(data) {
console.log('send email function');
let email = new AWS.SES({apiVersion: '2010-12-01'}).sendEmail(createEmailParams(buildEmail(data))).promise();
email.then(
function(res) {
console.log(res.MessageId); // works
return res.MessageId; // undefined
}).catch(
function(err) {
console.error('problems', err, err.stack);
return `Error! ${err}, ${err.stack}`;
});
}
in the console I always get:
send email function
undefined
0101017865c6f27b-955661fb-af47-4490-8eb6-7b59a0ec3414-000000
the guid thing is the console log of res.MessageId (email was successful). Undefined is the console log in the first function logging the result. I can see undefined show slightly before the messageid so I think the sendEmail function is not waiting for the emailer to complete.
Fairly sure the functions in the sendEmail function createEmailParams(buildEmail(data) aren't the problem, if I delete them then I still get undefined returned instead of the error message.
On face value it doesn't look like you're returning the promise to be awaited up stream of sendEmailFunction, nor is it being awaited in the function itself. Consider awaiting the response and returning it in sendEmailFunction, or returning the email promise and letting the upstream function await it and tease out the value it's looking for.
For example:
module.exports = async function sendEmailFunction(data) {
console.log('send email function');
let email = new AWS.SES({apiVersion: '2010-12-01'}).sendEmail(createEmailParams(buildEmail(data))).promise();
let response = await email.then(
function(res) {
console.log(res.MessageId); // works
return res.MessageId; // undefined
}).catch(
function(err) {
console.error('problems', err, err.stack);
return `Error! ${err}, ${err.stack}`;
});
return response; }

Firestore realtime listener error unhandled in node.js

I have made a function that I am exporting using node.js called return_match_uid. I am importing the function in another express routing file and am using async await, with try and catch to handle the error. But somehow, the errors produced by return_match_uid always slip and are unhandled, even though I am using the error handling for the realtime listener recommended by Firestore doc
Here is the function:
exports.return_match_uid = function return_match_uid() {
return new Promise((resolve, reject) => {
const unsub = db.collection('cities').onSnapshot(() => {
throw ("matching algo error");
resolve();
unsub();
}, err => {
console.log(err);
})
})
})
In another express router file, I am calling the function:
const Router = require('express').Router;
const router = new Router();
const {return_match_uid} = require("./match_algo");
router.get('/match', async (req, res) => {
try {
var match_user = await return_match_uid(req.query.data, req.query.rejected);
res.send(match_user);
}
catch (error) {
console.log("Matching algorithm return error: " + error);
}
})
The error I am throwing inside the function: matching algo error do not get caught by either the err => {console.log(err);}) in the function nor the try catch block in the router. It slips and causes my app to crash. It shows the following error:
throw "matching algo error!";
^
matching algo error!
(Use `node --trace-uncaught ...` to show where the exception was thrown)
[nodemon] app crashed - waiting for file changes before starting...
I am throwing an error inside matching algo error because I have some other codes in there, and there is a possibility that it produces an error. If it does, I would like to make sure that it gets handled properly.

Why error message is displayed on console when controller throws a method supertest

I am writing integration test for a nodejs/sails js application, where I have an Async controller method/route that throws error when input parameters are not provided.
I am using supertest to write integration test, everything works fine from my perspective, but when the test run error is written onto the console.
describe("a controller method", () => {
it("should throw error message", () => {
server('127.0.0.1')
.get('url to getData')
.set('Cookie', 'cookie token')
.end((err, res) => {
if(err) return done(err);
//console.log(res);
expect(res.status).to.equal(500);
expect(res.body).to.have.property('error', 'Provide a jobName');
done();
});
});
});
This following piece of code works fine cause I wrap this within an anonymous function and expect that function to throw. But I am not sure how to assert against those error.
it("throws", () => {
expect( function () {
server('127.0.0.1')
.get('some url')
.set('Cookie', 'cookie token')
}).to.throw;
});
The controller code looks like following. This is the method that is being called when URL end is requested.
getData : async (req, res) => {
let jobName = req.params.jobName || '',
buildId = req.params.buildId || '';
if(!jobName.trim() ){
return res.negotiate({error:'Provide a jobName'});
}
if(isNaN(buildId)) {
return res.negotiate({error:'Invalid build id supplied.'});
}
try {
let rawResult = await getData(jobName, buildId);
let promotions = formatData(rawResult);
let result = {
total : promotions.length || 0,
items : promotions
};
return res.json(result);
} catch(error) {
sails.log.error(`Request Parameter: Job name = ${req.param('jobName')} & build id = ${req.param('buildId')}`);
sails.log.error(error);
return res.negotiate({error: sails.config.errorMessage});
}
}
Why is the error being written to console ? What am I doing wrong here?
Any help/pointer is highly appreciated!!
How are you sending that error from express? In general express follows the way of passing errors rather than throwing it, for any errors in the program you can pass the error object to 'next' function. http://expressjs.com/en/guide/error-handling.html
e.g
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
async returns a promise and although you have placed a try catch block, my guess is the error is not in the block. It is most likely due to the promise rejection not getting handled.
The below should be of help to you as applying to the sails context.
since async functions return a promise, you need to .catch() any
promise rejections and pass them along to next(). Express error
handlers are only triggered by errors passed to next(), not exceptions
that you throw. Source
And for promise()=> reject

Can't set headers after they are sent in ftp library

I am using ftp library on npm. I am facing this error
_http_outgoing.js:357
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:357:11)
at ServerResponse.header (/Users/nomanmaqsood/Documents/netsuite-ftp/node_modules/express/lib/response.js:730:10)
First time I get proper response from the library on second call my node app crash due to the above error. Here is my code kindly guide me where is the mistake
c.on ('ready', function () {
c.list (function (err, list) {
if (err) {
c.end();
} else {
if (list.length > 0) {
c.end();
return res.status(200).json({data:list});//crash here on 2nd call
}
}
});
});
please help me out
Check that you don't call res.json or res.send twice on one client http request.
Try
c.on ('ready', function () {
c.list (function (err, list) {
if (err)
return res.status(500).json({error: err.message});
c.end();
res.status(200).json({data: list || []});
});
});
P.S. I suppose that you use Express.
the c was global object, which register itself twice. just make the object local and things works like charm

Categories