Initializing Firebase Function Calls in SwiftUI

Initializing Firebase Function Calls in SwiftUI

Get the region right...

When calling HTTPSCallable Firebase Functions from SwiftUI, if you don't configure the functions with the correct region, you can get too many https redirects.

In my App, BallFields, the deletion of a Team Schedule Entry causes delete of that Firestore Document and the sub-collections of the document (availability etc.)

To achieve this, I handle the deletion asynchronously on the server. A pathway is formed in the view model code and then this Cloud Function is called.

exports.deleteCollection = functions.region("us-east4").runWith({
    timeoutSeconds: 30,
    memory: '2GB'
  }).https.onCall(async (data, context)=>{

    if (!(context.auth && context.auth.token)) {
        throw new functions.https.HttpsError(
          'permission-denied',
          'Must be an administrative user to initiate delete.'
        );
      }
      const path = data.path;
      console.log(
        `User ${context.auth.uid} has requested to delete path ${path}`
      );

    await firebase_tools.firestore
      .delete(path, {
        project: process.env.GCLOUD_PROJECT,
        recursive: true,
        force: true,
        token: functions.config().fb.token
      });

    return {
      path: path 
    };
});

Initially, the calling code looked like this:

func deleteScheduleEntry(teamID: String, scheduleID: String)
    async throws {
        lazy var functions = Functions.functions()
        guard teamID != "" else { return }
        guard scheduleID != "" else { return }
        let availabilityPath = "/teams/\(teamID)/schedule/\(scheduleID)/availability"
        do {

            let _ = try? await functions.httpsCallable("deleteCollection").call(["path": availabilityPath])

            try await COLLECTION_TEAMS.document(teamID).collection("schedule").document(scheduleID).delete()
        } catch {
            throw error
        }
    }

However, this code would always return an error of https too many redirects. After troubleshooting I found that the FirebaseApp object which is created by the lazy var functions = Functions.functions() call was referencing the app in a different default region, in this case, "us-central1". This mismatch was causing the error. Simply changing the variable definition to include the same region the function was located, eliminated the redirects. The new function only needed one change in the code.

func deleteScheduleEntry(teamID: String, scheduleID: String)
    async throws {
        var functions = Functions.functions(region: "us-east4")
        guard teamID != "" else { return }
        guard scheduleID != "" else { return }
        let availabilityPath = "/teams/\(teamID)/schedule/\(scheduleID)/availability"
        do {

            let _ = try? await functions.httpsCallable("deleteCollection").call(["path": availabilityPath])

            try await COLLECTION_TEAMS.document(teamID).collection("schedule").document(scheduleID).delete()
        } catch {
            throw error
        }
    }

If you've stumbled here, I hope this saves you some time.