I am calling the following cloud function from my Angular application, but the value returned is always null even though the cloud function is correctly logging the result. Not sure what I am doing incorrectly.
My Angular code is as follows:
const data = {test: testToProcess};
const process = this.fns.httpsCallable("gprocess"); // fns is Angular Fire Functions
process(data)
.toPromise() // since Angular Fire function returns an observable, Iam converting to a promise
.then(
(result) => {
console.log("function called: " + JSON.stringify(result));
},
(err) => {
console.log("Function call error " + JSON.stringify(err));
}
);
My cloud functions code is as follows:
import * as functions from "firebase-functions";
const fs = require("fs");
const { google } = require("googleapis");
const script = google.script("v1");
const scriptId = "MY_SCRIPT_ID";
export const gprocess = functions.https.onCall(async (data: any, context: any) => {
const test = data.test;
return fs.readFile("gapi_credentials.json", (err: any, content: string) => {
if (err) {return err;}
const credentials = JSON.parse(content); // load the credentials
const { client_secret, client_id, redirect_uris } = credentials.web;
const googleAuth = require("google-auth-library");
const functionsOauth2Client = new googleAuth.OAuth2Client(client_id, client_secret, redirect_uris); // Constuct an auth client
functionsOauth2Client.setCredentials({refresh_token: credentials.refresh_token,}); // Authorize a client with credentials
return runScript(functionsOauth2Client,scriptId,JSON.stringify(test))
.then((scriptData: any) => {
console.log("Script data in main function is" + JSON.stringify(scriptData));
return scriptData;
})
.catch((error) => {return error;});
});
});
function runScript(auth: any, scriptid: string, test: any) {
return new Promise(function (resolve, reject) {
script.scripts.run({
auth: auth,
scriptId: scriptid,
resource: {function: "doGet",devMode: true,parameters: test}
})
.then((err: any, respons: any) => {
if (err) {
console.log("API returned an error: " + JSON.stringify(err));
resolve(err);
} else if (respons) {
console.log("Script is run and response is " + JSON.stringify(respons));
resolve(respons);
}
});
});
}
The angular function is returning this result before the processing on the cloud function can be completed. IT is not waiting for the results to be returned from the cloud function.
detailed.component.ts:691 function called: null
After some time the results are logged on the cloud function console but this is not returned back to the angular client. The log on the cloud function is as follows and as shown below the correct result is logged:
5:53:32.633 PM gpublish Function execution started
5:53:32.694 PM gpublish Function execution took 61 ms, finished with status code: 204
5:53:33.185 PM gpublish Function execution started
5:53:33.804 PM gpublish Function execution took 620 ms, finished with status code: 200
5:54:31.494 PM gpublish Script is run and response is : {"config":... some result}
5:54:31.593 PM gpublish Script data in main function is{"config":... some result}
Please help!
Your function is not correctly returning a promise that resolves to the data to serialize and send to the client. The problem is that fs.readFile doesn't actually return a promise. It's asychronous and returns nothing, and that's what the client will receive. The callback is being invoked, but nothing inside that callback will affect what the client sees.
You will need to find another way of doing your file I/O that is either synchronous (such as fs.readFileSync), or actually works with promises instead of just an async callback.