Firebase function not returning data - node.js

I'm trying to get data from my Firebase function, but it keeps returning a null response. It looks like I need to return a promise and return my data in that promise, but I can't seem to get it to work even though I think I'm doing that. I'm not the most familiar with Node.JS, so I might be returning the wrong things in the promise.
Here's my function code:
exports.tasksLists = functions.region('us-east1').https.onCall((data) => {
const userDoc = db.collection('users').doc(data.text);
return userDoc.get().then((doc) => {
if (!doc.exists) {
return "";
} else {
return doc.data().tasksKey;
}
}).then((tasksCreds) => {
const oauth2Client = new google.auth.OAuth2(
'444701140384-srcttdrg28geg598h65dkekad47u9a48.apps.googleusercontent.com',
'wNL4ZrBGYOnXUMvEcE7Z_Smo',
'https://collag-oauth-u5b2i5chyq-ue.a.run.app/classroomcallback'
);
oauth2Client.setCredentials({
refresh_token: tasksCreds.refresh_token,
access_token: tasksCreds.token
});
const service = google.tasks({ version: 'v1', auth: oauth2Client });
return service.tasklists.list({}, (err, res) => {
if (err) {
functions.logger.error(new Error(err));
return JSON.stringify(err);
}
const lists = res.data.items;
if (lists) {
functions.logger.info(lists);
return lists;
} else {
functions.logger.info('no lists');
return "No lists";
}
});
})
.catch((e) => {
functions.logger.error(new Error(e));
return JSON.stringify(e);
});;
});
I've also tried putting the OAuth and API request in the first .then() under else but that didn't work either.
Here's my frontend code to call the function and handle the data:
let tasksLists = fireApp.functions('us-east1').httpsCallable('tasksLists');
tasksLists({ text: currentUser.uid }).then(function (result) {
if (!result.data) {
console.log('no data');
}
let lists = result.data;
console.log(lists);
});
The console.log(lists) just outputs null.

The problem is that you're not returning a promise. You can use the Promise constructor, passing in the resolve/reject parameters and call any of those when your want to return the asynchronous result. Change your cloud function like so:
exports.tasksLists = functions.region('us-east1').https.onCall((data) => {
const userDoc = db.collection('users').doc(data.text);
return new Promise((resolve, reject) => {
userDoc.get().then((doc) => {
if (!doc.exists) {
return "";
} else {
return doc.data().tasksKey;
}
}).then((tasksCreds) => {
const oauth2Client = new google.auth.OAuth2(
'444701140384-srcttdrg28geg598h65dkekad47u9a48.apps.googleusercontent.com',
'wNL4ZrBGYOnXUMvEcE7Z_Smo',
'https://collag-oauth-u5b2i5chyq-ue.a.run.app/classroomcallback'
);
oauth2Client.setCredentials({
refresh_token: tasksCreds.refresh_token,
access_token: tasksCreds.token
});
const service = google.tasks({ version: 'v1', auth: oauth2Client });
service.tasklists.list({}, (err, res) => {
if (err) {
functions.logger.error(new Error(err));
// return JSON.stringify(err);
reject(err);
}
const lists = res.data.items;
if (lists) {
functions.logger.info(lists);
resolve(lists);
// return lists;
} else {
functions.logger.info('no lists');
resolve("No lists")
// return "No lists";
}
});
})
.catch((e) => {
functions.logger.error(new Error(e));
reject(e);
// return JSON.stringify(e);
});
})
});

Related

When trying to write image file it moves ahead and write works late

What i am trying to do here is i am writing a image file after resizing it with node and after that i will use it to upload it. but when i am writing it my uploading code started at that time and file is still not written.
async function getdataFromJimpSmall(image,filePath,FILE_NAME){
try{
var isSucess = false ;
const im = await Jimp.read(image);
return new Promise((resolve, reject) => {
try{
im.resize(150, 215, Jimp.RESIZE_BEZIER, function(err){
if (err) throw err;
});
im.write(filePath+FILE_NAME)
resolve(true)
}
catch(err){
console.log(err);
reject(false);
}
})
}
catch(err){
console.log('getdataFromJimpSmall Err====>'+err)
return false
}
}
I tried to use this but it is getting ahead of my code
it started from here and it is getting called from here.
isThumbnailUrlavailable = await jimpController.imageCoverJimpAndUploadToS3small(getISBNBook, "-#gmail.com", "SaleIsbn")
isThumbnailUrlavailableMedium = await jimpController.imageCoverJimpAndUploadToS3medium(getISBNBook, "-#gmail.com", "SaleIsbn")
And the first function imageCoverJimpAndUploadToS3small() is this:
exports.imageCoverJimpAndUploadToS3small = async (getContent,email,file) =>{
try{
var elementType = 15;
var filePath = path.join(__dirname, '../../uploads/t/')
var FILE_NAME = `${getContent.contentMetaDataRef.isbn}_s.jpg`
var image = getContent.thumbnail
let tempdata = await getdataFromJimpSmall(image,filePath,FILE_NAME)
console.log('temp - ', tempdata);
if(tempdata==true)
{
var data = await commonController.uploadthumbnailTOPublicS3(filePath, FILE_NAME)
console.log('s3', data);
requestImageSize(data.url).then(size =>
{
console.log(size);
if(size.height>0&&size.width>0)
{
tempdata=true;
const getContentElement = ContentElement.findOne({contentId: getContent._id,elementType,elementData: data.keyName}).lean()
if(getContentElement){
ContentElement.findByIdAndUpdate(getContentElement._id, {
createdOn: Date(), modifiedOn: Date(),
}, { new: true })
}
else
{
return tempdata;
}else
{
tempdata=false;
return tempdata;
}
}).catch(err =>
{
console.error(err);
tempdata=false;
return tempdata;
});
}
}
catch(error){
console.log(error)
tempdata=false;
return tempdata;
}
}
But it is not working...
Again i am calling imageCoverJimpAndUploadToS3small() and it starts after that.
as per docs https://www.npmjs.com/package/jimp#writing-to-files-and-buffers, .write runs asynchronously and takes a callback, which is why the promise resolves before image is written
so, you need to use callback, and resolve from there:
im.write(filePath+FILE_NAME, (err)=>{
if(err) throw err;
resolve(true);
});
or, as the docs say, you might use and await .writeAsync, which is promise-based:
await im.writeAsync(filePath+FILE_NAME);
resolve(true);

problem in sending base64 data in GET request

Hi I am facing issues sending base64 data in GET request.
I was successful in converting the image into base64 data and inserting it in receivedFile
but during response the attachments come as an empty array while the rest of the data i.e user_id is flowing successfully.
Hence if you could please help me to resolve this issue.
Below is the code
router.js
router.get('/users/data/expand/:nid',async (req,res) => {
var idselected = req.params.nid;
var dir = '\images';
var receivedFile = [];
try {
const checkData = await user.find({"user_id": idselected});
await checkData[0].attachments.forEach (element => {
fs.readdir(dir,function(err,files) {
if(err) {
console.log(err)
}else {
files.forEach((filename) => {
filename = element;
fs.readFile(filename,'base64', (err,base64Data) => {
if(err) {
console.log(err);
}
receivedFile.push(base64Data);
})
})
}
})
})
//issue is here the attachments is coming as empty instead of base64 data
const returnUser = new User({
user_id: checkData.user_id,
attachments: receivedFile
})
res.status(201).send(returnUser);
}
catch(e) {
res.status(500).send(e)
}
})
Well its always good to create helper functions and to promisfy it so you can use async / await syntax.
I have changed your code. I didnt tested it but i guess it should work:#
router.get("/users/data/expand/:nid", async (req, res) => {
var idselected = req.params.nid;
var dir = "images";
try {
const checkData = await user.findOne({ user_id: idselected });
let receivedFile = await Promise.all(
checkData.attachments.flatMap(async element => {
let files = await readDirectory(dir);
return await Promise.all(
files.map(filename => {
filename = element;
return readFile(filename)
})
);
})
);
const returnUser = new User({
user_id: checkData.user_id,
attachments: receivedFile
});
let savedUser = await returnUser.save();
res.status(201).send(savedUser);
} catch (e) {
res.status(500).send(e);
}
});
function readDirectory(dir) {
return new Promise((res, rej) => {
fs.readdir(dir, function(err, files) {
if (err) {
rej(err);
} else {
res(files);
}
});
});
}
function readFile(filename) {
return new Promise((res, rej) => {
fs.readFile(filename, "base64", (err, base64Data) => {
if (err) {
rej(err);
}
res(base64Data);
});
});
}
I guess you use mongoose.
There is an method called findOne and also you forgot to save your model with returnUser.save()

why does my nodejs function returning undefined?

function getUserByStudentId(NIM) {
db.query('SELECT * FROM data_admin WHERE id_mahasiswa = ?', [NIM], async (err, result) => {
if (!result) {
return null
} else {
var data = await {
id: result[0].id_Admin,
email: result[0].email,
jabatan: result[0].jabatan,
password: result[0].password,
id_mahasiswa: result[0].id_mahasiswa,
id_Acara: result[0].id_Acara,
id_Organisasi: result[0].id_Organisasi
}
console.log(data) // there is a value here
return data
}
})
}
console.log(getUserByStudentId('1301194051')) // undefined returned
I'm a student and start learning nodejs. Would you explain to me, why my function returning undefined
console.log(getUserByStudentId('1301194051')) // undefined
but when I console.log on the function I got returned value
I'll promisify the function for you:
function getUserByStudentId(NIM) {
return new Promise(function(resolve, reject) => {
db.query('SELECT * FROM data_admin WHERE id_mahasiswa = ?', [NIM], (err, result) => {
if (!result) {
resolve(null);
} else {
var data = {
id: result[0].id_Admin,
email: result[0].email,
jabatan: result[0].jabatan,
password: result[0].password,
id_mahasiswa: result[0].id_mahasiswa,
id_Acara: result[0].id_Acara,
id_Organisasi: result[0].id_Organisasi
}
console.log(data) // there is a value here
resolve(data);
}
});
});
}
If you're going to use this function in global scope, use then:
getUserByStudentId('1301194051').then(result => {
console.log(result);
});
If you want to use this function inside an async function, you can await the result:
async function doSomethingWithUser(NIM) {
const user = await getUserByStudentId(NIM);
}
For example, if you're using express:
app.get('/user/:id', async (res, req) => {
const NIM = req.param.id;
const user = await getUserByStudentId(NIM);
res.json({ user });
});

async/await for aws sdk function

I am using a custom auth challenge to get the otp as response, with below code I am able to get the OTP. But, instead of promise how can I use async/await to get the response from intiateAuth.
const params = {
AuthFlow: ".......",
ClientId: "*********",
AuthParameters: {
"USERNAME": req.userName,
}
};
return new Promise((resolve, reject) => {
new AWS.CognitoIdentityServiceProvider().initiateAuth(params, (err, data) => {
if (err) {
console.log("Error in adminInitiateAuth: %s", err.message);
reject(false);
} else {
const otpResponse: IOTPResponseDetails = {
session: data.Session,
userName: data.ChallengeParameters.USERNAME,
}
resolve(otpResponse);
}
});
});
}```
Create an async function. Use "await" inside a try/catch block to capture any errors.
const params = {
AuthFlow: ".......",
ClientId: "*********",
AuthParameters: {
"USERNAME": req.userName,
}
};
// Async function using await
const execute = async(parameters) => {
try {
const data = await new AWS.CognitoIdentityServiceProvider().initiateAuth(parameters);
const otpResponse: IOTPResponseDetails = {
session: data.Session,
userName: data.ChallengeParameters.USERNAME,
};
return otpResponse;
} catch (err) {
console.log("Error in adminInitiateAuth: %s", err.message);
throw new Error(err.message);
}
}
// Call async function with params as argument
await execute(params);

Callback error handler didn't stop execute function

I'm trying to develop an API post, in middle execution I have validation such as check name already in use or not. I set error handler callback, it successfully send response 'Already registered', but when I checked to CLI, it show error
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I dont know whats wrong, I use this error handler in the past and it seems look ok.
Here is my code in router:
createUserAccount: async function (req, res) {
const programData = req.body;
try {
await service.create(programData, function (code, err, result) {
if (err) {
if(code === 409){
res.status(HTTPSTATUS.CONFLICT).send(err.message);
} else {
res.status(HTTPSTATUS.BAD_REQUEST).send(err.message);
}
} else {
res.status(HTTPSTATUS.CREATED).json(result);
}
})
} catch (e) {
console.log(e)
res.status(HTTPSTATUS.BAD_REQUEST).json("Failed.");
}
Here is my function in my service:
const config = require('#configs/config.json')
const sequelize = require('sequelize');
const SEQUELIZE = new sequelize(config[env]);
module.exports = {
createAccount: async (name, password, callback) => {
try {
let check,
institution_id;
const checkName = await Profile.count(
{
where: {
name: name
}
}
);
//result checkName = 1
if(checkName > 0){
//then successfully execute this condition and
return callback(409, 'Already registered.', null);
//this show in console ----> POST /API/v1/user/profile 409 616.152 ms - 31
}
await Login.create({
username: email,
password: password
}).then(resLogin => {
const response = {
id: resLogin.id,
}
callback(201, null, response);
}).catch( error => {
callback(400, error, null);
})
} catch (e) {
callback(400, e, null);
}
},
create: async (payload, callback) => {
let loginID = null;
let {
profile,
address
} = payload;
let {
name,
email,
password
} = profile;
try {
await module.exports.createAccount(name, password, function (code, error, result) {
if(error){
const res = {message: error};
//what I need is the execution is end in here
return callback(code, res, null);
}
loginID = result.id;
});
//but the fact is it still execute this whole function if got callback error from createAccount()
let transaction = await SEQUELIZE.transaction();
await Address.create(address, {transaction})
.then( async resAddress => {
await transaction.commit();
return callback(201, null, resProfile);
}).catch(async e => {
return callback(400, e, null);
})
} catch (e) {
console.log(e);
callback(e, null);
}
};

Resources