Reputation: 637
I am rather new to Firebase/Firestore/Cloud functions and been trying a little project where a client app calls a Firebase Cloud Function to generate some random keys (random numbers), adds them to Firestore, and when successfully written, returns these keys to the client app. Kinda like a random number generator.
The function is called correctly by the client (according to Firebase Console), does generate the keys, checks if they exist in the Firestore, and if not adds them. All works up to the part where it should return the result to the client. Here the client never gets the result (the keys array). In fact, the callback in the client app (iOS/Swift) is never called.
I am suspecting the problem lies in the promise being returned? According to the Firebase documentation here, async callables should return a Promise although I am not entirely sure what I am doing is correct https://firebase.google.com/docs/functions/callable
Here is the code for the cloud function:
export const generateRandomKeys = functions.https.onCall(async (data, context) => {
// Read data passed from client
const numberOfKeys = data.numberOfKeys
console.log("Number of keys to generate: ", numberOfKeys)
// Generate some keys
const generatedKeys = KeyMaker.newKeys(numberOfKeys)
try {
const randomkeys = []
// Write keys to DB
for (const key of generatedKeys) {
const addedKey = await writeKeyToDB(key)
randomkeys.push(addedKey)
}
return Promise.resolve(JSON.stringify(randomkeys))
} catch (error) {
console.log("Error has occured: ", error)
throw new Error("An Error has occured: " + error)
}
})
async function writeKeyToDB(key: string){
try {
// Check if a document with the same key already exists in the DB
const docRef = db.collection("randomKeys").doc(key)
const doc = await docRef.get()
// Document with same key found!
if (doc.exists) {
// Generate a new key and try again
const newKey = KeyMaker.newKey()
console.log("Will generate a new key and try again!. New key: ", newKey)
await writeKeyToDB(newKey)
}
const keyDoc = {
somefield: somevalue,
}
// Write to DB then return result
await docRef.set(keyDoc)
return Promise.resolve(key)
} catch (error) {
return Promise.reject(error)
}
}
Client (Swift)
public static func generateNewRandomNumbers(numberOfKeys: Int) {
FirebaseApp.configure()
let functions = Functions.functions(region: FIRESTORE_REGION)
functions.httpsCallable("generateRandomKeys").call(["numberOfKeys": numberOfKeys]) { (result, error) in
// Nothing here executes
print("----------got reply---------")
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
print("Error \(String(describing: code)): " + message)
}
}
if let keys = (result?.data as? [String]) {
dump(keys)
}
}
}
Upvotes: 3
Views: 1422
Reputation: 637
Finally found the issue, thanks for Doug and Dominik for guiding me in the right direction. I removed the promises and returned directly the values but more importantly, I didn't need to convert the array to JSON. I came across HTTPSCallableResult documentation
I simply changed this
return JSON.stringify(randomkeys);
to
return randomkeys
and on the client, instead of
if let keys = (result?.data as? [String]) {
dump(keys)
}
I do
if let keys = (result?.data as? NSArray) {
dump(keys)
}
Upvotes: 0
Reputation: 1602
Dont combine Async/Await
and Promise
. Async
functions as itself returning Promise
.
First change return of your cloud function to :
return JSON.stringify(randomkeys);
Also in writeKeyToDb
change return to:
return key;
and catch
part to:
throw Error(error);
I see also problem that in cloud function you calling your writeKeyToDb
function with 2 parameters, but that function have only one. But that code probably is in progress
Upvotes: 1