Call functions from your app

The Cloud Functions for Firebase client SDKs let you call functions directly from a Firebase app. To call a function from your app in this way, write and deploy an HTTPS Callable function in Cloud Functions, and then add client logic to call the function from your app.

It's important to keep in mind that HTTPS callable functions are similar but not identical to HTTP functions. Also, note that the callback signature has changed between v1 and v2:

// Adds two numbers to each other.
exports.addnumbers = onCall((request) => {
  // Numbers passed from the client.
  const firstNumber = request.data.firstNumber;
  const secondNumber = request.data.secondNumber;

  // Checking that attributes are present and are numbers.
  if (!Number.isFinite(firstNumber) || !Number.isFinite(secondNumber)) {
    // Throwing an HttpsError so that the client gets the error details.
    throw new HttpsError("invalid-argument", "The function must be called " +
            "with two arguments \"firstNumber\" and \"secondNumber\" which " +
            "must both be numbers.");
  }

  // returning result.
  return {
    firstNumber: firstNumber,
    secondNumber: secondNumber,
    operator: "+",
    operationResult: firstNumber + secondNumber,
  };
});

Until Cloud Functions v2 supports cloudfunctions.net URLs, you will have to use a different initializer in your client code. Rather than providing a function name, provide a full URL to the client SDK. The URL for your function is printed at the end of a successful firebase deploy command:

Function URL (shoulddance(us-west1)): https://shoulddance-uvb3o4q2mq-uw.a.run.app

Callables have these key differences from HTTP functions:

  • With callables, Firebase Authentication tokens, FCM tokens, and App Check tokens, when available, are automatically included in requests.
  • The functions.https.onCall trigger automatically deserializes the request body and validates auth tokens.

The Firebase SDK for Cloud Functions v2 and higher interoperates with these Firebase client SDK minimum versions to support HTTPS Callable functions:

  • Firebase SDK for Apple platforms 9.2.0
  • Firebase SDK for Android 20.1.0
  • Firebase Modular Web SDK v. 9.7.0

If you want to add similar functionality to an app built on an unsupported platform, see the Protocol Specification for https.onCall. The rest of this guide provides instructions on how to write, deploy, and call an HTTPS callable function for Apple platforms, Android, web, C++, and Unity.

Write and deploy the callable function

Use the onCall method of the functions/v2/https subpackage to create an HTTP callable function. This method takes an event parameter with data, auth, app, and instanceToken properties:

// Saves a message to the Firebase Realtime Database but sanitizes the
// text by removing swearwords.
exports.addmessage = onCall((request) => {
  // ...
});

For a callable function that saves a text message to the Realtime Database, for example, data could contain the message text, along with auth information in auth:

// Message text passed from the client.
const text = request.data.text;
// Authentication / user information is automatically added to the request.
const uid = request.auth.uid;
const name = request.auth.token.name || null;
const picture = request.auth.token.picture || null;
const email = request.auth.token.email || null;

Distance between the location of the callable function and the location of the calling client can create network latency. To optimize performance, consider specifying the function location where applicable, and make sure to align the callable's location with the location set when you initialize the SDK on the client side.

Optionally, you can attach an App Check attestation to help protect your backend resources from abuse, such as billing fraud or phishing. See Enable App Check enforcement for Cloud Functions.

Sending back the result

To send data back to the client, return data that can be JSON encoded. For example, to return the result of an addition operation:

// returning result.
return {
  firstNumber: firstNumber,
  secondNumber: secondNumber,
  operator: "+",
  operationResult: firstNumber + secondNumber,
};

To return data after an asynchronous operation, return a promise. The data returned by the promise is sent back to the client. For example, you could return sanitized text that the callable function wrote to the Realtime Database:

// Saving the new message to the Realtime Database.
const sanitizedMessage = sanitizer.sanitizeText(text); // Sanitize message.

return getDatabase().ref("/messages").push({
  text: sanitizedMessage,
  author: {uid, name, picture, email},
}).then(() => {
  logger.info("New Message written");
  // Returning the sanitized message to the client.
  return {text: sanitizedMessage};
})

Handle errors

To ensure the client gets useful error details, return errors from a callable by throwing (or returning a Promise rejected with) an instance of functions.https.HttpsError. The error has a code attribute that can be one of the values listed at functions.https.HttpsError. The errors also have a string message, which defaults to an empty string. They can also have an optional details field with an arbitrary value. If an error other than HttpsError is thrown from your functions, your client instead receives an error with the message INTERNAL and the code internal.

For example, a function could throw data validation and authentication errors with error messages to return to the calling client:

// Checking attribute.
if (!(typeof text === "string") || text.length === 0) {
  // Throwing an HttpsError so that the client gets the error details.
  throw new HttpsError("invalid-argument", "The function must be called " +
          "with one arguments \"text\" containing the message text to add.");
}
// Checking that the user is authenticated.
if (!request.auth) {
  // Throwing an HttpsError so that the client gets the error details.
  throw new HttpsError("failed-precondition", "The function must be " +
          "called while authenticated.");
}

Deploy the callable function

After you save a completed callable function within index.js, it is deployed along with all other functions when you run firebase deploy. To deploy only the callable, use the --only argument as shown to perform partial deploys:

firebase deploy --only functions:addMessage

If you encounter permissions errors when deploying functions, make sure that the appropriate IAM roles are assigned to the user running the deployment commands.

Set up your client development environment

Make sure you meet any prerequisites, then add the required dependencies and client libraries to your app.

iOS+

Follow the instructions to add Firebase to your Apple app.

Use Swift Package Manager to install and manage Firebase dependencies.

  1. In Xcode, with your app project open, navigate to File > Add Packages.
  2. When prompted, add the Firebase Apple platforms SDK repository:
  3.   https://github.com/firebase/firebase-ios-sdk
  4. Choose the Cloud Functions library.
  5. When finished, Xcode will automatically begin resolving and downloading your dependencies in the background.

Web version 9

  1. Follow the instructions to add Firebase to your Web app. Make sure to run the following command from your terminal:
    npm install firebase@9.8.4 --save
    
  2. Manually require both Firebase core and Cloud Functions:

     import { initializeApp } from 'firebase/app';
     import { getFunctions } from 'firebase/functions';
    
     const app = initializeApp({
         projectId: '### CLOUD FUNCTIONS PROJECT ID ###',
         apiKey: '### FIREBASE API KEY ###',
         authDomain: '### FIREBASE AUTH DOMAIN ###',
       });
     const functions = getFunctions(app);
    

Java

  1. Follow the instructions to add Firebase to your Android app.

  2. Using the Firebase Android BoM, declare the dependency for the Cloud Functions Android library in your module (app-level) Gradle file (usually app/build.gradle).

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:30.1.0')
    
        // Declare the dependency for the Cloud Functions library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-functions'
    }
    

    By using the Firebase Android BoM, your app will always use compatible versions of the Firebase Android libraries.

    (Alternative) Declare Firebase library dependencies without using the BoM

    If you choose not to use the Firebase BoM, you must specify each Firebase library version in its dependency line.

    Note that if you use multiple Firebase libraries in your app, we highly recommend using the BoM to manage library versions, which ensures that all versions are compatible.

    dependencies {
        // Declare the dependency for the Cloud Functions library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-functions:20.1.0'
    }
    

Kotlin+KTX

  1. Follow the instructions to add Firebase to your Android app.

  2. Using the Firebase Android BoM, declare the dependency for the Cloud Functions Android library in your module (app-level) Gradle file (usually app/build.gradle).

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:30.1.0')
    
        // Declare the dependency for the Cloud Functions library
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-functions-ktx'
    }
    

    By using the Firebase Android BoM, your app will always use compatible versions of the Firebase Android libraries.

    (Alternative) Declare Firebase library dependencies without using the BoM

    If you choose not to use the Firebase BoM, you must specify each Firebase library version in its dependency line.

    Note that if you use multiple Firebase libraries in your app, we highly recommend using the BoM to manage library versions, which ensures that all versions are compatible.

    dependencies {
        // Declare the dependency for the Cloud Functions library
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation 'com.google.firebase:firebase-functions-ktx:20.1.0'
    }
    

Initialize the client SDK

Initialize an instance of Cloud Functions:

Swift

lazy var functions = Functions.functions()

Objective-C

@property(strong, nonatomic) FIRFunctions *functions;
// ...
self.functions = [FIRFunctions functions];

Web version 9

const app = initializeApp({
  projectId: '### CLOUD FUNCTIONS PROJECT ID ###',
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
});
const functions = getFunctions(app);

Java

private FirebaseFunctions mFunctions;
// ...
mFunctions = FirebaseFunctions.getInstance();

Kotlin+KTX

private lateinit var functions: FirebaseFunctions
// ...
functions = Firebase.functions

Call the function

Swift

let addMessageURL = URL(string: "https://addmessage-xyz1234-uc.a.run.app/addMessage")!

functions.httpsCallable(addMessageURL).call(["text": inputField.text]) { result, error in
  if let error = error as NSError? {
    if error.domain == FunctionsErrorDomain {
      let code = FunctionsErrorCode(rawValue: error.code)
      let message = error.localizedDescription
      let details = error.userInfo[FunctionsErrorDetailsKey]
    }
    // ...
  }
  if let data = result?.data as? [String: Any], let text = data["text"] as? String {
    self.resultField.text = text
  }
}

Web version 9

import { getFunctions, httpsCallableFromURL } from 'firebase/functions';

const functions = getFunctions();
const addMessage = httpsCallableFromURL(
  functions,
  // the URL of the function
  "https://addmessage-xyz1234-uc.a.run.app/addMessage"
);

addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    const data = result.data;
    const sanitizedMessage = data.text;
  });

Kotlin+KTX

private fun addMessage(text: String): Task<String> {
    // Create the arguments to the callable function.
    val data = hashMapOf(
        "text" to text,
        "push" to true
    )

    return functions
            // The URL of the function
            .getHttpsCallableFromUrl(URL("https://addmessage-xyz1234-uc.a.run.app/addMessage"))
            .call(data)
            .continueWith { task ->
                // This continuation runs on either success or failure, but if the task
                // has failed then result will throw an Exception which will be
                // propagated down.
                val result = task.result?.data as String
                result
            }
}

Handle errors on the client

The client receives an error if the server threw an error or if the resulting promise was rejected. If the error returned by the function is of type function.https.HttpsError, then the client receives the error code, message, and details from the server error. Otherwise, the error contains the message INTERNAL and the code INTERNAL. See guidance for how to handle errors in your callable function.

Swift

if let error = error as NSError? {
  if error.domain == FunctionsErrorDomain {
    let code = FunctionsErrorCode(rawValue: error.code)
    let message = error.localizedDescription
    let details = error.userInfo[FunctionsErrorDetailsKey]
  }
  // ...
}

Web version 9

import { getFunctions, httpsCallableFromURL } from "firebase/functions";

const functions = getFunctions();
const addMessage = httpsCallableFromURL(
  functions,
  // the URL of the function
  "https://addmessage-xyz1234-uc.a.run.app/addMessage"
);

addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    const data = result.data;
    const sanitizedMessage = data.text;
  })
  .catch((error) => {
    // Getting the Error details.
    const code = error.code;
    const message = error.message;
    const details = error.details;
    // ...
  });

Kotlin+KTX

addMessage(inputMessage)
    .addOnCompleteListener { task ->
        if (!task.isSuccessful) {
            val e = task.exception
            if (e is FirebaseFunctionsException) {
                val code = e.code
                val details = e.details
            }
        }
    }

Before you launch your app, you should enable App Check to help ensure that only your apps can access your callable function endpoints.