Lee Probert
Lee Probert

Reputation: 10839

Firebase Function returns null data object

I have a Firebase Cloud Function that works (it writes to my database as Admin, and also checks for an existing entry with an email string ID). My issue is that it doesn't return the data back to the client app properly.

When I trace the value of result it is {data: null}

I would also like to throw an error if the email exists, but it complains about an unhandled promise (see the comments in the code below).

So there are two questions here. The first being the most pressing.

exports.saveData = functions.https.onCall( (data, context) => {

    // check if the email exists
    admin.database().ref('competition_entries/' + data.compId + '/' + data.emailStringId).once('value').then(function(snapshot) {
        if (snapshot.val() == null){

          console.log("Writing data to "+data.compId+" : "+data.emailStringId);

          let current_datetime = new Date()
          let formatted_time = current_datetime.getHours() + ":" + current_datetime.getMinutes() + ":" + current_datetime.getSeconds();
          let formatted_date = current_datetime.getDate() + "/" + (current_datetime.getMonth() + 1) + "/" + current_datetime.getFullYear();
          let timestamp_string = formatted_time+" "+formatted_date;
          console.log(formatted_date)

          admin.database().ref('competition_entries/' + data.compId + '/' + data.emailStringId).set({
            name: data.name,
            email: data.email,
            phone: data.phone,
            selectedItem: data.selectedItem,
            submitted_date: timestamp_string
          })
          .then(() => {
            console.log("success");
            return {
              "error": "none",
              "message": "success"
            };
          }).catch(function(error) {
            throw error;
          });

        }else{
            // email address exists as a data entry so tell the user that they have already submitted
            let code = "already-exists";
            let message = "Email address already exists";
            let details = "A user with the same email address has already entered the competition.";
            console.log(message+"/"+details);

            /*
              TODO: throwing an HttpsError directly here was causing an unresolved promise error. This would be the better way to tell the client that the user has already submitted their data.
            */
            // throw error;
            //throw new functions.https.HttpsError(code, message, details);

            // this resolves the promise error but is a hack
            return {
              error: new functions.https.HttpsError(code, message, details),
              message: message
            }
        }
    }).catch(function(error) {
      throw error;
    });
});

Upvotes: 1

Views: 558

Answers (1)

cutiko
cutiko

Reputation: 10497

I think the problem is you are not returning enough. Functions needs every function to return something to execute succesfully.

Commonly is return true or return Promise

So it should be something like this:

//check if email exist
return admin.databse...

    //If there is no user create it
     return.admin...

The code does write the database but since it was no return that happened asynchronously, and the code would keep executing from top to bottom making the function to response jibberish to the client.

You should

  • if (!snapshot) shortcircuiting is better because snapshot could be undefined causing an exception when checkinf if snapshot data is null
  • You dont need to use the admin sdk for the database, Functions is considered a trusted enviroments so operations are runned with admin privileges. You can CRUD anything despite rules or user restrictions

Upvotes: 3

Related Questions