Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node/Firebase onCall asynchronous function return

The user types a message into a chat client (a website). This message is sent through to a cloud function set up on firebase. The cloud function then queries a 3rd party API which returns a response. This response needs to be sent back to the client to be displayed.

So basically my client calls a cloud function like so...

var submitMessage = firebase.functions().httpsCallable('submitMessage');
submitMessage({message: userMessage}).thenfunction(result) {
  //Process result
});

My cloud function looks like this...

exports.submitMessage = functions.https.onCall((data, context) => {
  request({
    url: URL,
    method: "POST",
    json: true,
    body: queryJSON //A json variable I've built previously
  }, function (error, response, body) {
    //Processes the result (which is in the body of the return)
  });

return {response: "Test return"};
});

I have included the request package and the API call itself works perfectly. I can print the result to the console from within the return function of the request. However, obviously because the request is asynchronous I can't just create a global variable and assign the result body to it. I have seen that you can call a callback function once the request is finished. However, I need to somehow pass that through to the cloud function return value. So put simply, I need to do this...

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

var gBody;

request({
    url: URL,
    method: "POST",
    json: true,
    body: queryJSON //A json variable I've built previously
  }, function (error, response, body) {
    gBody = body;
  });

return gBody;
});

(Yes, I am aware of this post... How do I return the response from an asynchronous call? but yeah as I said I need the variable scope to be within the cloud function itself so that I am able to return the value back to the client. Either I don't understand the methods used in that post or it does not accomplish what I am asking)

like image 419
Bulleyeaccuracy Avatar asked Aug 26 '18 22:08

Bulleyeaccuracy


1 Answers

The approach in your last snippet can't work: by the time your return gBody runs the callback from the 3rd party API hasn't been called yet, so gBody is empty.

As the Cloud Functions documentation says:

To return data after an asynchronous operation, return a promise. The data returned by the promise is sent back to the client.

So you just return a promise, and then later resolve that promise with the data from the 3rd party API.

exports.submitMessage = functions.https.onCall((data, context) => {
  return new Promise(function(resolve, reject) {
    request({
      url: URL,
      method: "POST",
      json: true,
      body: queryJSON //A json variable I've built previously
    }, function (error, response, body) {
      if (error) {
        reject(error);
      } 
      else {
        resolve(body)
      } 
    });
  });
});
like image 186
Frank van Puffelen Avatar answered Nov 05 '22 10:11

Frank van Puffelen