I am calling a third-party API via Axios async-await, and returning the result to a flutter application via a google cloud function. I am forced to use functions.https.onCall
because flutter can't call onRequest
functions as far as I know.
The result is shown correctly in console.log
in the logs of the cloud function but when the flutter app calls the function, it's always receiving null
. Why?
getSmsBalance: functions.https.onCall(async (data, context) => {
const business_id = data.business_id;
const collectionRef = db.collection("buser_sms");
const snapshot = await collectionRef.where("id", "==", business_id).get();
if (snapshot.empty) {
console.log("No matching documents - getSMSBalance .");
let response = {
status: false,
};
return JSON.stringify(response);
}
snapshot.forEach((doc) => {
if (
doc.data().enableReservationSms == true ||
doc.data().enableAutoReminder == true ||
doc.data().enableReminderSms == true
) {
// get balance
(async () => {
const balance = await getBalance(
doc.data().senderId,
doc.data().username,
doc.data().password
)
.then((result) => {
let response = {
status: true,
data: result,
};
console.log("balance is " + result);
return JSON.stringify(response);
})
.catch((err) => {
console.error(`Error - getSmsBalance - ${err}`);
let response = {
status: false,
};
return JSON.stringify(response);
});
})();
}
});
}),
There are several issues with your code:
Array.forEach
which does not allow to await because of its intrinsic design. If you want to use async/await within the loop iterations, you need to use Array.map
for example. But in most cases, you shouldn't use async/await inside a loop because it removes the advantages of asynchronous code execution (each iteration is only triggered after the previous one).snapshot.empty
. The return
s in the then
and catch
callbacks only assign the values to the variable balance
which isn't used afterwards.So in conclusion, you need to use something like:
return Promise.all(
snapshot.map((doc) => {
return getBalance(
doc.data().senderId,
doc.data().username,
doc.data().password
)
.then((result) => {
let response = {
status: true,
data: result,
};
console.log('balance is ' + result);
return JSON.stringify(response);
})
.catch((err) => {
console.error(`Error - getSmsBalance - ${err}`);
let response = {
status: false,
};
return JSON.stringify(response);
});
})
);
Note that I'm providing that code snipped without any consideration for what format you actually need as the output. Having an array of response
s may not be what you need. But you should be able to adapt that code to what you need in the end.