Firebase function not returning value - node.js

I am trying to do some operations using oncall function where,
I am first checking if user exists in database, then if he exists then do some operations like updating the DB.
well the function is working as expected and updating the DB as well, but its returning response as null so I can't tell what exactly happening.
exports.populateCart = functions.https.onCall((data, context) => {
const user = context.auth.uid;
DB.collection('users').doc(user).get().then((usr_resp) => {
if (usr_resp.exists) {
DB.collection('products').doc(data.productKey).get().then((prod_res) => {
DB.collection('carts').add({
//some data
}).then(() => {
return {
response: 'CART UPDATED'
};
}).catch((carts_err) => {
return {
response: 'ERROR WHILE POPULATING CART : ' + carts_err
}
});
}).catch((prod_err) => {
return {
response: 'ERROR WHILE FETCHING PRODUCT : ' + prod_err
};
});
}
else {
return {
response: 'USER DOES NOT EXISTS OR USER NOT AUTHENTICATED'
};
}
}).catch((usr_err) => {
return {
response: 'ERROR WHILE FETCHING USER : ' + usr_err
};
});
});
There is one more similar question on stack overflow, where the solution is proposed to use,
reject(err);
resolve(lists);
methods, Please if the solution is using above methods, then please explain the use cases of this method in detail and if there are more methods like this please explain them as well.
Firebase function not returning data

You need to return every promise that you are running:
exports.populateCart = functions.https.onCall((data, context) => {
const user = context.auth.uid;
return DB.collection('users').doc(user).get().then((usr_resp) => {
if (usr_resp.exists) {
return DB.collection('products').doc(data.productKey).get().then((prod_res) => {
return DB.collection('carts').add({
//some data
}).then(() => {
return {
response: 'CART UPDATED'
};
}).catch((carts_err) => {
return {
response: 'ERROR WHILE POPULATING CART : ' + carts_err
}
});
}).catch((prod_err) => {
return {
response: 'ERROR WHILE FETCHING PRODUCT : ' + prod_err
};
});
}
else {
return {
response: 'USER DOES NOT EXISTS OR USER NOT AUTHENTICATED'
};
}
}).catch((usr_err) => {
return {
response: 'ERROR WHILE FETCHING USER : ' + usr_err
};
});
});
Try copying the above code. Also using async functions will make it look better like this:
exports.populateCart = functions.https.onCall(async (data, context) => {
try {
const usr_resp = await DB.collection('users').doc(user).get()
if (!usr_resp.exists) throw new Error("USER DOES NOT EXISTS OR USER NOT AUTHENTICATED")
const prod_res = await DB.collection('products').doc(data.productKey).get()
await DB.collection('carts').add({ . someData . })
return { response: "Cart Updated" }
} catch (e) {
console.log(e)
return { response: e }
}
});

You are not returning your promise. (see line 3 below)
exports.populateCart = functions.https.onCall((data, context) => {
const user = context.auth.uid;
// add return here before Db.collection()
return DB.collection('users').doc(user).get().then((usr_resp) => {
if (usr_resp.exists) {
return DB.collection('products').doc(data.productKey).get().then((prod_res) => {
return DB.collection('carts').add({
//some data
}).then(() => {
return {
response: 'CART UPDATED'
};
}).catch((carts_err) => {
return {
response: 'ERROR WHILE POPULATING CART : ' + carts_err
}
});
}).catch((prod_err) => {
return {
response: 'ERROR WHILE FETCHING PRODUCT : ' + prod_err
};
});
}
else {
return {
response: 'USER DOES NOT EXISTS OR USER NOT AUTHENTICATED'
};
}
}).catch((usr_err) => {
return {
response: 'ERROR WHILE FETCHING USER : ' + usr_err
};
});
});

Related

Non-admin User checkout (Create Order) -- Product is not defined

I am a webdev student trying to create an Ecommerce -API with Node and Express JS connected with MongoDB but I am getting this return in postman : "Product is not defined" in my Non_Admin Checkout function.
I don't really know what my mistakes are. Can you help me?
Here are my codes:
UserController
module.exports.checkout = async (data) => {
try{
let is_user_updated = await User.findById(data.userId).then((user) => {
user.orders.push({productId: data.productId})
return user.save().then((updated_user, error) => {
if(error){
return false
}
return true
})
})
}catch(err){return err.message}
try{
let is_product_updated = await Product.findById(data.productId).then((product) => {
product.orders.push({userId:data.userId})
return ordered.save().then((updated_product, error) => {
if(error){
return false
}
return true
})
})
}catch(err){return err.message}
if(is_user_updated && is_product_updated){
return {
message: 'User checkout is successful!'
}
}
return {
message: 'Something went wrong.'
}
}

telegraf how to check if user is admin?

i have this code:
function isAdmin(idOfChat, IdOfUser, ctx) {
//function
return isAdminBoolean
}
bot.command("test", ctx => {
if (isAdmin(ctx.message.chat.id, ctx.message.from.id) == true) {
ctx.reply("Admin")
}else{
ctx.reply("._.")
}
})
how to make it work?
sorry for my bad English)))
You should re-write your method as a promise (because Telegraf queries from Telegram API, so, your isAdmin method could be like this)
function isAdmin(idOfChat, IdOfUser, ctx) {
return new Promise((resolve, reject) => {
//Get user information first
ctx.telegram.getChatMember(idOfChat, IdOfUser).then((user) => {
//Then check if user is admin (or creator)
resolve(user.status == "administrator" || user.status == "creator");
})
.catch((error) => {
//Reject if it's an error
reject(error);
});
});
}
Then, for use it into your main function, you should have to handle it like this:
bot.command("test", ctx => {
isAdmin(ctx.message.chat.id, ctx.message.from.id, ctx).then((result) => {
if (result) {
ctx.reply("Admin");
} else {
ctx.reply("._.");
}
})
.catch((error) => {
ctx.reply("An error has ocurred trying to get user rank: " + JSON.stringify(error));
});
});

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

What is the proper way to execute axios / firebase promises in a specific order in a firebase function?

What is the best way to chain axios / firebase promises that must be linked in a specific order and use the returns of previous promises?
I am writing a firebase function that allows me to update a user via a third-party JWT API. So I have to fulfill several promises (I use axios for that) to build the final query with a uid, a token and a refresh token.
These requests must be executed in the right order, each promise waiting for the result of the previous one to be able to execute.
recover the firebase client token to identify the user
search in a collection for the tokens (access & refresh) that were previously stored and associated with the user's uid.
Execute the "me" request on the third-party API to retrieve the user's information and update the user.
My question: What is the most correct way to chase these axios promises?
For the moment, I have managed to achieve this result, by interlocking the calls successively to properly manage the "catch" and by moving in separate functions the calls to make a little more digest the reading of the code.
/* index.js */
const userModule = require('./user');
exports.me = functions.https.onRequest( (request, response) => {
cors(request, response, () => {
let idToken = request.body.data.token;
userModule
.get(idToken)
.then((uid) => {
console.log('User found : ' + uid);
return userModule
.retrieve(uid)
.then((userTokens) => {
console.log('User tokens found : ' + userTokens.token);
return userModule
.me(userTokens.token, uid)
.then((me) => {
return me;
}).catch((error) => {
return response.status(404).json({
data : {
error : 404,
message : 'NO_USER_ON_API'
}
});
})
}).catch((error) => {
console.log(error);
return response.status(404).json({
data : {
error : 404,
message : 'NO_TOKEN_USER_FOUND'
}
});
})
})
.catch((error) => {
console.log(error);
return response.status(500).json({
data : {
error : 500,
message : 'USER_TOKEN_NO_MATCH'
}
});
})
.then((user) => {
if(user.data !== undefined)
{
return response.status(200).json({
data : {
user : user.data
}
});
}
else
{
return response.status(204).json({
data : {
user : null
}
});
}
})
});
});
/* user.js */
exports.get = (firebaseToken) {
return admin.auth().verifyIdToken(firebaseToken)
.then(function(decodedToken) {
return decodedToken.uid;
})
.catch(function(error) {
throw {
code: 500,
body: "INTERNAL_ERROR"
};
});
};
exports.retrieve = (uid) {
return admin.firestore().collection("AccessTokenCollection").doc(uid).get()
.then(function(docRef) {
return docRef.data();
})
.catch(function(error) {
throw {
code: 404,
body: "NO_USER_FOUND"
};
});
};
exports.me = (UserToken, uid) {
let params = {
params: {
},
headers: {
'Authorization': 'Bearer ' + UserToken
}
};
return axiosInstance.instance.get(url + '/users/me', params)
.then(userMe => {
return userMe;
})
.catch(errMe => {
console.log(errMe.response.status);
throw {
code: 401,
body: "EXPIRING_TOKEN"
};
});
};
Etc...
The code works as it is more a theoretical question or optimization!
const userModule = require('./user');
exports.me = functions.https.onRequest((request, response) => {
cors(request, response, async () => {
let idToken = request.body.data.token;
try {
let uid = await userModule.get(idToken);
console.log('User found : ' + uid);
let userTokens = await userModule.retrieve(uid);
console.log('User tokens found : ' + userTokens.token);
let meObj = await userModule.me(userTokens.token, uid);
} catch (error) {
console.log('error', error);
}
});
});
So, here using async-await i have removed then-catch block. await keyword will work as then and will only move forward to second call after first call has been completed. And i have made a common catch block for error handling which you can modified according to your needs
you can use promise.all and async-await instead of then and catch

Server sends success even if didn't find anything

I send data from my input fields to my api:
$.ajax({
url: '/api/login',
type: 'GET',
dataType: 'json',
ContentType: 'application/json',
data: {formData},
success: (data) => {
console.log('SUCCESS')
console.log(data)
this.setState({
isInProcess: false
})
},
error: (jqXHR) => {
console.log(jqXHR)
console.log('ERROR')
this.setState({isInProcess: false})
}
})
on my server-side I have a function to see if I have required user in db:
async function findUser(data) {
try {
const user = await User.findOne({email: data.email,
password: data.password})
console.log('User was found')
return { user }
} catch (err) {
console.log('error', err)
throw err
}
}
which will be executed here:
app.get('/api/login', async (req, res) => {
const data = req.query
try {
const foundUserData = await findUser(data.formData)
return res.json(foundUserData)
} catch (err) {
return res.status(400).json(err)
}
})
It works fine, but if a user wasn't found in db i sends success anyway. Why?
await findUser(data.formData) won't throw error, return either null or user object. You may check something following
app.get('/api/login', async (req, res) => {
const data = req.query
try {
const foundUserData = await findUser(data.formData)
if(foundUserData && foundUserData.user) {
return res.json(foundUserData)
} else {
return res.status(400).json({message: 'User not found'});
}
} catch (err) {
return res.status(500).json(err)
}
})
It sends success because none of your queries error'ed, just because it didn't find anything does not mean that the query failed because it obviously succeeded in finding out if what ever you're looking for exists or not.
To send an error in case of not found you need to check if response is empty in which case you want to send error
When no user is find you get a null value. You may try to put more logic on your success parameter with that for example:
success: function (data) {
if(!!data && data != null) {
alert('Success');
} else {
alert('No data');
}
}

Resources