7

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)

1 Answer 1

14

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)
      } 
    });
  });
});
Sign up to request clarification or add additional context in comments.

4 Comments

Cheers for the help mate! How would I process this promise on the client though?
The result of a promise is sent back to the client the exact same way as for a regular return.
Edit Sorry for bad formatting, I'm pretty new to this forum. I've tried doing the following but doesn't work... submitMessage({message: userMessage{).then(function(result) { result.then(function(result) { console.log(result); }); });
Never mind, I didn't realise the result could be read like a regular JSON variable. result.data gives you what was originally retrieved from the 3rd party API. Cheers for your help mate!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.