Home > Software engineering >  Google cloud functions: functions.https.onCall returning null but the value is shown correctly in th
Google cloud functions: functions.https.onCall returning null but the value is shown correctly in th

Time:04-24

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

CodePudding user response:

There are several issues with your code:

  1. You are using async/await syntax inside an 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).
  2. You don't return anything from your function, except in the case of snapshot.empty. The returns 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.docs.map(function (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 responses may not be what you need. But you should be able to adapt that code to what you need in the end.

  • Related