فراخوانی توابع از برنامه

کیت‌های توسعه نرم‌افزار مشتری Cloud Functions for Firebase به شما امکان می‌دهند توابع را مستقیماً از برنامه Firebase فراخوانی کنید. برای فراخوانی تابع از برنامه خود به این روش، یک تابع قابل فراخوانی HTTP را در Cloud Functions بنویسید و مستقر کنید، و سپس منطق مشتری را برای فراخوانی تابع از برنامه خود اضافه کنید.

باید به‌خاطر داشته باشید که توابع قابل‌فراخوانی HTTP مشابه توابع HTTP هستند اما با آن‌ها یکسان نیستند. برای استفاده از توابع قابل‌فراخوانی HTTP، باید از کیت توسعه نرم‌افزار کارخواه برای پلاتفرم خود به‌همراه میانای برنامه‌سازی کاربردی پس‌بست استفاده کنید (یا پروتکل را پیاده‌سازی کنید). توابع قابل‌فراخوانی این تفاوت کلیدی را با توابع HTTP دارند:

  • با فراخوانی‌ها، درصورت دردسترس بودن، توکن‌های Firebase Authentication، توکن‌های FCM، و توکن‌های App Check به‌طور خودکار در درخواست‌ها گنجانده می‌شوند.
  • راه‌انداز به‌طور خودکار بدنه درخواست را غیرسریالی می‌کند و درستی نشان‌های اصالت‌سنجی را می‌سنجد.

کیت توسعه نرم‌افزار Firebase برای نسل دوم Cloud Functions و بالاتر با این حداقل نسخه‌های کیت توسعه نرم‌افزار مشتری Firebase برای پشتیبانی از توابع قابل‌فراخوانی HTTPS تعامل‌پذیر است:

  • Firebase کیت توسعه نرم‌افزار برای پلاتفرم‌های Apple نسخه ۱۳.۰.۰
  • کیت توسعه نرم‌افزار Firebase برای Android نسخه ۲۳.۰.۰
  • Firebase Modular Web SDK v. 9.7.0

اگر می‌خواهید عملکرد مشابهی را به برنامه‌ای که در پلاتفرم پشتیبانی‌نشده‌ای ساخته شده است اضافه کنید، مشخصات پروتکل برای https.onCall را ببینید. بقیه این راهنما دستورالعمل‌هایی درباره نحوه نوشتن، استقرار، و فراخوانی تابع فراخوانی HTTP برای پلاتفرم‌های Apple،‏ Android، وب، C++‎، و Unity ارائه می‌دهد.

نوشتن و استقرار تابع قابل‌فراخوانی

نمونه‌های کد در این بخش براساس یک نمونه شروع سریع کامل است که نشان می‌دهد چگونه بااستفاده از یکی از کیت‌های توسعه نرم‌افزار کارخواه، درخواست‌ها را به یک تابع سمت سرور ارسال کنید و پاسخ دریافت کنید. برای شروع، ماژول‌های موردنیاز را وارد کنید:

Node.js

// Dependencies for callable functions.
const {onCall, HttpsError} = require("firebase-functions/https");
const {logger} = require("firebase-functions");

// Dependencies for the addMessage function.
const {getDatabase} = require("firebase-admin/database");
const sanitizer = require("./sanitizer");

پایتون

# Dependencies for callable functions.
from firebase_functions import https_fn, options

# Dependencies for writing to Realtime Database.
from firebase_admin import db, initialize_app

Dart (آزمایشی)

// Dependencies for callable functions.
import 'package:firebase_functions/firebase_functions.dart';

از کنترل‌کننده درخواست برای پلاتفرم خود استفاده کنید تا تابع قابل‌فراخوانی HTTPS ایجاد کنید. این روش پارامتر درخواست را می‌گیرد:

Node.js

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

پایتون

@https_fn.on_call()
def addmessage(req: https_fn.CallableRequest) -> Any:
    """Saves a message to the Firebase Realtime Database but sanitizes the text
    by removing swear words."""

Dart (آزمایشی)

// Adds two numbers to each other.
firebase.https.onCall(name: 'addNumbers', (request, response) async {

پارامتر request حاوی داده‌های ارسال‌شده از برنامه مشتری و همچنین بافت اضافی مانند وضعیت اصالت‌سنجی است. برای تابع قابل‌فراخوانی که پیام نوشتاری را در Realtime Database ذخیره می‌کند، برای مثال، data می‌تواند حاوی نوشتار پیام، به‌همراه اطلاعات اصالت‌سنجی در auth باشد:

Node.js

// 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;

پایتون

# Message text passed from the client.
text = req.data["text"]
# Authentication / user information is automatically added to the request.
uid = req.auth.uid
name = req.auth.token.get("name", "")
picture = req.auth.token.get("picture", "")
email = req.auth.token.get("email", "")

Dart (آزمایشی)

// Numbers passed from the client.
final data = request.data as Map<String, Object?>?;
final firstNumber = data?['firstNumber'];
final secondNumber = data?['secondNumber'];
// Authentication / user information is automatically added to the request.
final uid = request.auth?.uid;
final token = request.auth?.token;
final name = token?['name'];
final picture = token?['picture'];
final email = token?['email'];

// Use variables to suppress 'unused' lint warnings
print(
  'User details: uid=$uid, name=$name, picture=$picture, email=$email',
);

فاصله بین مکان تابع قابل‌فراخوانی و مکان کارخواه فراخواننده می‌تواند تأخیر شبکه ایجاد کند. برای بهینه‌سازی عملکرد، درصورت لزوم، مکان تابع را مشخص کنید و مطمئن شوید که مکان قابل‌فراخوانی با مکان تنظیم‌شده هنگام راه‌اندازی کیت توسعه نرم‌افزار در سمت کارخواه مطابقت داشته باشد.

درصورت تمایل، می‌توانید App Check گواهی پیوست کنید تا به محافظت از منابع پسین شما دربرابر سوءاستفاده، مانند کلاهبرداری صورت‌حسابی یا رمزگیری، کمک کند. اجرای App Check برای Cloud Functions فعال شود را ببینید.

ارسال نتیجه

برای ارسال داده‌ها به مشتری، داده‌هایی را برگردانید که بتوانند با JSON کدگذاری شوند. برای مثال، برای برگرداندن نتیجه عملیات جمع:

Node.js

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

پایتون

return {
    "firstNumber": first_number,
    "secondNumber": second_number,
    "operator": "+",
    "operationResult": first_number + second_number,
}

Dart (آزمایشی)

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

نوشتار پاک‌سازی‌شده از نمونه نوشتار پیام هم به کارخواه و هم به Realtime Database برگردانده می‌شود. در Node.js، این کار را می‌توان به‌صورت ناهمگام بااستفاده از JavaScript promise انجام داد:

Node.js

// 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};
})

پایتون

# Saving the new message to the Realtime Database.
sanitized_message = sanitize_text(text)  # Sanitize message.
db.reference("/messages").push(
    {  # type: ignore
        "text": sanitized_message,
        "author": {"uid": uid, "name": name, "picture": picture, "email": email},
    }
)
print("New message written")

# Returning the sanitized message to the client.
return {"text": sanitized_message}

تابع شما باید مقداری را برگرداند یا درمورد Node.js، یک Promise که با یک مقدار حل می‌شود. درغیراین‌صورت، ممکن است تابع قبل‌از ارسال داده‌ها به مشتری خاتمه یابد. برای راهنمایی، به پایان دادن به عملکردها مراجعه کنید.

ارسال و دریافت نتایج جاری‌سازی

توابع قابل‌فراخوانی سازوکارهایی برای مدیریت نتایج جاری‌سازی دارند. اگر مورد استفاده‌ای دارید که به جاری‌سازی نیاز دارد، می‌توانید جاری‌سازی را در درخواست قابل‌فراخوانی پیکربندی کنید و سپس از روش مناسب از کیت توسعه نرم‌افزار کارخواه برای فراخوانی تابع استفاده کنید.

ارسال نتایج جاری‌سازی

برای جاری‌سازی مؤثر نتایجی که درطول زمان تولید می‌شوند، مثلاً از تعدادی درخواست API جداگانه یا یک API هوش مصنوعی زایا، ویژگی acceptsStreaming را در درخواست قابل‌فراخوانی خود بررسی کنید. وقتی این ویژگی روی true تنظیم شده باشد، می‌توانید نتایج را با response.sendChunk() به کارخواه برگردانید.

برای مثال، اگر برنامه‌ای نیاز به بازیابی داده‌های پیش‌بینی آب‌وهوا برای چندین مکان داشته باشد، تابع فراخوانی‌شدنی می‌تواند پیش‌بینی هر مکان را به‌طور جداگانه به مشتریانی که درخواست پاسخ جاری‌سازی کرده‌اند ارسال کند، به‌جای اینکه آن‌ها را منتظر بگذارد تا همه درخواست‌های پیش‌بینی حل شوند:

exports.getForecast = onCall(async (request, response) => {
  if (request.data?.locations?.length < 1) {
    throw new HttpsError("invalid-argument", "Missing locations to forecast");
  }

  // fetch forecast data for all requested locations
  const allRequests = request.data.locations.map(
      async ({latitude, longitude}) => {
        const forecast = await weatherForecastApi(latitude, longitude);
        const result = {latitude, longitude, forecast};

        // clients that support streaming will have each
        // forecast streamed to them as they complete
        if (request.acceptsStreaming) {
          response.sendChunk(result);
        }

        return result;
      },
  );

  // Return the full set of data to all clients
  return Promise.all(allRequests);
});

توجه داشته باشید که نحوه عملکرد response.sendChunk() به جزئیات خاصی از درخواست کارخواه بستگی دارد:

  1. اگر کارخواه درخواست پاسخ جاری‌سازی کند: response.sendChunk(data) بخش داده را فوراً ارسال می‌کند.

  2. اگر کارخواه پاسخ جاری‌سازی را درخواست نکند: response.sendChunk() برای آن فراخوانی کاری انجام نمی‌دهد. وقتی همه داده‌ها آماده شد، پاسخ کامل ارسال می‌شود.

برای تعیین اینکه آیا کارخواه درخواست پاسخ جاری‌سازی دارد یا نه، ویژگی request.acceptsStreaming را بررسی کنید. برای مثال، اگر request.acceptsStreaming نادرست باشد، ممکن است تصمیم بگیرید از هرگونه کار پرمصرف ازنظر منابع که به‌طور خاص به آماده‌سازی یا ارسال بخش‌های جداگانه مربوط می‌شود صرف‌نظر کنید، زیرا کارخواه انتظار تحویل افزایشی را ندارد.

دریافت نتایج جاری‌سازی

در یک سناریوی معمول، مشتری با روش .stream درخواست جاری‌سازی می‌کند و سپس نتایج را تکرار می‌کند:

Swift

func listenToWeatherForecast() async throws {
    isLoading = true
    defer { isLoading = false }

    Functions
      .functions(region: "us-central1")
    let getForecast: Callable<WeatherRequest, StreamResponse<WeatherResponse, [WeatherResponse]>> = Functions.functions().httpsCallable("getForecast")

    let request = WeatherRequest(locations: locations)
    let stream = try getForecast.stream(request)

    for try await response in stream {
      switch response {
      case .message(let singleResponse):
        weatherData["\(singleResponse.latitude),\(singleResponse.longitude)"] = singleResponse
      case .result(let arrayOfResponses):
        for response in arrayOfResponses {
          weatherData["\(response.latitude),\(response.longitude)"] = response
        }
        print("Stream ended.")
        return
      }
    }
  }

Web

// Get the callable by passing an initialized functions SDK.
const getForecast = httpsCallable(functions, "getForecast");

// Call the function with the `.stream()` method to start streaming.
const { stream, data } = await getForecast.stream({
  locations: favoriteLocations,
});

// The `stream` async iterable returned by `.stream()`
// will yield a new value every time the callable
// function calls `sendChunk()`.
for await (const forecastDataChunk of stream) {
  // update the UI every time a new chunk is received
  // from the callable function
  updateUi(forecastDataChunk);
}

// The `data` promise resolves when the callable
// function completes.
const allWeatherForecasts = await data;
finalizeUi(allWeatherForecasts);

همان‌طور که نشان داده شده است، در تکرارپذیر ناهمگام stream حلقه ایجاد کنید. منتظر ماندن برای data promise به کارخواه نشان می‌دهد که درخواست تکمیل شده است

Kotlin

// Get the callable by passing an initialized functions SDK.
val getForecast = functions.getHttpsCallable("getForecast");

// Call the function with the `.stream()` method and convert it to a flow
getForecast.stream(
  mapOf("locations" to favoriteLocations)
).asFlow().collect { response ->
  when (response) {
    is StreamResponse.Message -> {
      // The flow will emit a [StreamResponse.Message] value every time the
      // callable function calls `sendChunk()`.
      val forecastDataChunk = response.message.data as Map<String, Any>
      // Update the UI every time a new chunk is received
      // from the callable function
      updateUI(
        forecastDataChunk["latitude"] as Double,
        forecastDataChunk["longitude"] as Double,
        forecastDataChunk["forecast"] as Double,
      )
    }
    is StreamResponse.Result -> {
      // The flow will emit a [StreamResponse.Result] value when the
      // callable function completes.
      val allWeatherForecasts = response.result.data as List<Map<String, Any>>
      finalizeUI(allWeatherForecasts)
    }
  }
}

برای استفاده از تابع افزونه asFlow()، کتابخانه org.jetbrains.kotlinx:kotlinx-coroutines-reactive را به‌عنوان وابستگی به فایل build.gradle(.kts) برنامه اضافه کنید.

Java

// Get the callable by passing an initialized functions SDK.
HttpsCallableReference getForecast = mFunctions.getHttpsCallable("getForecast");
getForecast.stream(
  new HashMap<String, Object>() {{
    put("locations", favoriteLocations);
  }}
).subscribe(new Subscriber<StreamResponse>() {
  @Override
  public void onSubscribe(Subscription subscription) {
    subscription.request(Long.MAX_VALUE);
  }

  @Override
  public void onNext(StreamResponse streamResponse) {
    if (streamResponse instanceof StreamResponse.Message) {
      // The flow will emit a [StreamResponse.Message] value every time the
      // callable function calls `sendChunk()`.
      StreamResponse.Message response = (StreamResponse.Message) streamResponse;
      Map<String, Object> forecastDataChunk =
        (Map<String, Object>) response.getMessage().getData();
      // Update the UI every time a new chunk is received
      // from the callable function
      updateUI(
        (double) forecastDataChunk.get("latitude"),
        (double) forecastDataChunk.get("longitude"),
        (double) forecastDataChunk.get("forecast")
      );
    } else if(streamResponse instanceof StreamResponse.Result) {
      // The flow will emit a [StreamResponse.Result] value when the
      // callable function completes.
      StreamResponse.Result response = (StreamResponse.Result) streamResponse;
      List<Map<String, Object>> allWeatherForecasts =
        (List<Map<String, Object>>) response.getResult().getData();
      finalizeUI();
    }
  }

  @Override
  public void onError(Throwable throwable) {
    // an error occurred in the function
  }

  @Override
  public void onComplete() {

  }
});

پیکربندی CORS (هم‌رسانی منبع میان‌مبدئی)

از گزینه cors برای کنترل اینکه کدام مبدأها می‌توانند به تابع شما دسترسی داشته باشند استفاده کنید.

به‌طور پیش‌فرض، توابع قابل‌فراخوانی دارای CORS پیکربندی‌شده هستند تا درخواست‌ها را از همه مبدأها مجاز کنند. برای مجاز کردن برخی‌از درخواست‌های میان‌مبدئی، اما نه همه آن‌ها، فهرستی از دامنه‌های خاص یا عبارت‌های باقاعده را که باید مجاز شوند ارسال کنید. برای مثال:

Node.js

const { onCall } = require("firebase-functions/v2/https");

exports.getGreeting = onCall(
  { cors: [/firebase\.com$/, "https://flutter.com"] },
  (request) => {
    return "Hello, world!";
  }
);

پایتون

from firebase_functions import https_fn, options

@https_fn.on_call(
    cors=options.CorsOptions(
        cors_origins=[r"firebase\.com$", r"https://flutter\.com"],
        cors_methods=["get", "post"],
    )
)
def say_hello(req: https_fn.CallableRequest) -> Any:
    return "Hello world!"

Dart (آزمایشی)

import 'package:firebase_functions/firebase_functions.dart';

void main(List<String> args) {
  fireUp(args, (firebase) {
    firebase.https.onCall(
      name: 'getGreeting',
      options: CallableOptions(
        cors: Cors([RegExp(r'^https:\/\/firebase\.com$'), 'https://flutter.com']),
      ),
      (request) async {
        return CallableResult('Hello, world!');
      },
    );
  });
}

برای ممنوع کردن درخواست‌های میان‌مبدئی، خط‌مشی cors را روی false تنظیم کنید.

مدیریت کردن خطاها

برای اطمینان از اینکه مشتری جزئیات خطای مفیدی دریافت می‌کند، خطاها را از یک فراخوانی با پرتاب کردن (یا برای Node.js برگرداندن یک Promise ردشده با) یک نمونه از functions.https.HttpsError یا https_fn.HttpsError برگردانید. خطا دارای مشخصه code است که می‌تواند یکی از مقادیر فهرست‌شده در کدهای وضعیت gRPC باشد. خطاها همچنین دارای رشته message هستند که به‌طور پیش‌فرض رشته‌ای خالی است. همچنین می‌توانند فیلد اختیاری details با مقدار دلخواه داشته باشند. اگر خطایی غیراز خطای HTTPS از توابع شما ایجاد شود، کارخواه شما درعوض خطایی با پیام INTERNAL و کد internal دریافت می‌کند.

برای مثال، یک تابع می‌تواند خطاهای اصالت‌سنجی و اعتبارسنجی داده را با پیام‌های خطا برای برگرداندن به کارخواه فراخواننده ایجاد کند:

Node.js

// 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.");
}

پایتون

# Checking attribute.
if not isinstance(text, str) or len(text) < 1:
    # Throwing an HttpsError so that the client gets the error details.
    raise https_fn.HttpsError(
        code=https_fn.FunctionsErrorCode.INVALID_ARGUMENT,
        message=(
            'The function must be called with one argument, "text",'
            " containing the message text to add."
        ),
    )

# Checking that the user is authenticated.
if req.auth is None:
    # Throwing an HttpsError so that the client gets the error details.
    raise https_fn.HttpsError(
        code=https_fn.FunctionsErrorCode.FAILED_PRECONDITION,
        message="The function must be called while authenticated.",
    )

Dart (آزمایشی)

// Checking that attributes are present and are numbers.
if (firstNumber is! num || secondNumber is! num) {
  // Throwing an HttpsError so that the client gets the error details.
  throw InvalidArgumentError(
    'The function must be called with two arguments "firstNumber" and "secondNumber" which must both be numbers.',
  );
}

استقرار تابع قابل‌فراخوانی

پس‌از ذخیره کردن تابع فراخوانی کامل‌شده در index.js، این تابع همراه با همه توابع دیگر هنگام اجرای firebase deploy مستقر می‌شود. برای استقرار فقط فراخوانی‌پذیر، از آرگومان --only همان‌طور که نشان داده شده است برای انجام استقرارهای جزئی استفاده کنید:

firebase deploy --only functions:addMessage

اگر هنگام استقرار توابع با خطاهای مربوط به اجازه‌ها مواجه شدید، مطمئن شوید که نقش‌های IAM مناسب به کاربری که فرمان‌های استقرار را اجرا می‌کند اختصاص داده شده باشد.

راه‌اندازی محیط توسعه نرم‌افزار کارخواه

مطمئن شوید که پیش‌نیازها را برآورده می‌کنید، سپس وابستگی‌های لازم و کتابخانه‌های کارخواه را به برنامه‌تان اضافه کنید.

iOS+‎

دستورالعمل‌های افزودن Firebase به برنامه Apple را دنبال کنید.

از Swift Package Manager برای نصب و مدیریت وابستگی‌های Firebase استفاده کنید.

  1. در Xcode، درحالی‌که پروژه برنامه‌تان باز است، به File (فایل) > Add Packages (افزودن بسته‌ها) بروید.
  2. وقتی خواسته شد، مخزن کیت توسعه نرم‌افزار Firebase برای پلاتفرم‌های Apple را اضافه کنید:
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. کتابخانه Cloud Functions را انتخاب کنید.
  5. پرچم -ObjC را به بخش Other Linker Flags (سایر پرچم‌های پیونددهنده) در تنظیمات ساخت هدف اضافه کنید.
  6. پس‌از اتمام، Xcode به‌طور خودکار شروع به حل و بارگیری وابستگی‌های شما در پس‌زمینه می‌کند.

Web

  1. دستورالعمل‌های افزودن Firebase به برنامه وب را دنبال کنید. حتماً فرمان زیر را از پایانه اجرا کنید:
    npm install firebase@13.0.0 --save
  2. به‌طور دستی هم هسته Firebase و هم 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);

Android

  1. دستورالعمل‌های افزودن Firebase به برنامه Android را دنبال کنید.

  2. در فایل Gradle (سطح برنامه) (معمولاً <project>/<app-module>/build.gradle.kts یا <project>/<app-module>/build.gradle)، وابستگی کتابخانه Cloud Functions را برای Android اضافه کنید. توصیه می‌کنیم از Firebase Android BoM برای کنترل نسخه‌بندی کتابخانه استفاده کنید.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:35.0.2"))
    
        // Add 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")
    }

    بااستفاده از Firebase Android BoM، برنامه شما همیشه از نسخه‌های سازگار کتابخانه‌های Firebase Android استفاده خواهد کرد.

    (جایگزین)  افزودن وابستگی‌های کتابخانه Firebase بدون استفاده از BoM

    اگر انتخاب کنید که از Firebase BoM استفاده نکنید، باید هر نسخه کتابخانه Firebase را در خط وابستگی آن مشخص کنید.

    توجه داشته باشید که اگر از چند کتابخانه Firebase در برنامه‌تان استفاده می‌کنید، اکیداً توصیه می‌کنیم از BoM برای مدیریت نسخه‌های کتابخانه استفاده کنید تا مطمئن شوید همه نسخه‌ها سازگار هستند.

    dependencies {
        // Add 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:23.0.0")
    }

مقداردهی اولیه کیت توسعه نرم‌افزار (SDK) مشتری

نمونه‌ای از Cloud Functions را مقداردهی اولیه کنید:

Swift

lazy var functions = Functions.functions()

Objective-C

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

Web

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

Kotlin

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

Java

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

فراخوانی تابع

Swift

functions.httpsCallable("addMessage").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
  }
}

Objective-C

[[_functions HTTPSCallableWithName:@"addMessage"] callWithObject:@{@"text": _inputField.text}
                                                      completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) {
  if (error) {
    if ([error.domain isEqual:@"com.firebase.functions"]) {
      FIRFunctionsErrorCode code = error.code;
      NSString *message = error.localizedDescription;
      NSObject *details = error.userInfo[@"details"];
    }
    // ...
  }
  self->_resultField.text = result.data[@"text"];
}];

Web

var addMessage = firebase.functions().httpsCallable('addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    var sanitizedMessage = result.data.text;
  });

Web

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

const functions = getFunctions();
const addMessage = httpsCallable(functions, 'addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    /** @type {any} */
    const data = result.data;
    const sanitizedMessage = data.text;
  });

Kotlin

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
        .getHttpsCallable("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
        }
}

Java

private Task<String> addMessage(String text) {
    // Create the arguments to the callable function.
    Map<String, Object> data = new HashMap<>();
    data.put("text", text);
    data.put("push", true);

    return mFunctions
            .getHttpsCallable("addMessage")
            .call(data)
            .continueWith(new Continuation<HttpsCallableResult, String>() {
                @Override
                public String then(@NonNull Task<HttpsCallableResult> task) throws Exception {
                    // This continuation runs on either success or failure, but if the task
                    // has failed then getResult() will throw an Exception which will be
                    // propagated down.
                    String result = (String) task.getResult().getData();
                    return result;
                }
            });
}

Dart

    final result = await FirebaseFunctions.instance.httpsCallable('addMessage').call(
      {
        "text": text,
        "push": true,
      },
    );
    _response = result.data as String;

C++‎

firebase::Future<firebase::functions::HttpsCallableResult> AddMessage(
    const std::string& text) {
  // Create the arguments to the callable function.
  firebase::Variant data = firebase::Variant::EmptyMap();
  data.map()["text"] = firebase::Variant(text);
  data.map()["push"] = true;

  // Call the function and add a callback for the result.
  firebase::functions::HttpsCallableReference doSomething =
      functions->GetHttpsCallable("addMessage");
  return doSomething.Call(data);
}

Unity

private Task<string> addMessage(string text) {
  // Create the arguments to the callable function.
  var data = new Dictionary<string, object>();
  data["text"] = text;
  data["push"] = true;

  // Call the function and extract the operation from the result.
  var function = functions.GetHttpsCallable("addMessage");
  return function.CallAsync(data).ContinueWith((task) => {
    return (string) task.Result.Data;
  });
}

رسیدگی به خطاها در کارخواه

اگر سرور خطایی ایجاد کند یا اگر وعده حاصل رد شود، کارخواه خطایی دریافت می‌کند.

اگر خطای برگردانده‌شده توسط تابع از نوع function.https.HttpsError باشد، کارخواه خطای code،‏ message، و details را از خطای سرور دریافت می‌کند. درغیراین‌صورت، خطا حاوی پیام INTERNAL و کد INTERNAL است. راهنمای نحوه رسیدگی به خطاها در تابع قابل‌فراخوانی را ببینید.

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]
  }
  // ...
}

Objective-C

if (error) {
  if ([error.domain isEqual:@"com.firebase.functions"]) {
    FIRFunctionsErrorCode code = error.code;
    NSString *message = error.localizedDescription;
    NSObject *details = error.userInfo[@"details"];
  }
  // ...
}

Web

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

Web

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

const functions = getFunctions();
const addMessage = httpsCallable(functions, 'addMessage');
addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    /** @type {any} */
    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

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

Java

addMessage(inputMessage)
  .addOnCompleteListener(new OnCompleteListener<String>() {
    @Override
    public void onComplete(@NonNull Task<String> task) {
      if (!task.isSuccessful()) {
        Exception e = task.getException();
        if (e instanceof FirebaseFunctionsException) {
          FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
          FirebaseFunctionsException.Code code = ffe.getCode();
          Object details = ffe.getDetails();
        }
      }
    }
  });

Dart

try {
  final result =
      await FirebaseFunctions.instance.httpsCallable('addMessage').call();
} on FirebaseFunctionsException catch (error) {
  print(error.code);
  print(error.details);
  print(error.message);
}

C++‎

void OnAddMessageCallback(
    const firebase::Future<firebase::functions::HttpsCallableResult>& future) {
  if (future.error() != firebase::functions::kErrorNone) {
    // Function error code, will be kErrorInternal if the failure was not
    // handled properly in the function call.
    auto code = static_cast<firebase::functions::Error>(future.error());

    // Display the error in the UI.
    DisplayError(code, future.error_message());
    return;
  }

  const firebase::functions::HttpsCallableResult* result = future.result();
  firebase::Variant data = result->data();
  // This will assert if the result returned from the function wasn't a string.
  std::string message = data.string_value();
  // Display the result in the UI.
  DisplayResult(message);
}

// ...

// ...
  auto future = AddMessage(message);
  future.OnCompletion(OnAddMessageCallback);
  // ...

Unity

 addMessage(text).ContinueWith((task) => {
  if (task.IsFaulted) {
    foreach (var inner in task.Exception.InnerExceptions) {
      if (inner is FunctionsException) {
        var e = (FunctionsException) inner;
        // Function error code, will be INTERNAL if the failure
        // was not handled properly in the function call.
        var code = e.ErrorCode;
        var message = e.ErrorMessage;
      }
    }
  } else {
    string result = task.Result;
  }
});

تنظیم زمان اتمام کارخواه

به‌طور پیش‌فرض، کیت‌های توسعه نرم‌افزار کارخواه Cloud Functions از زمان استراحت ۷۰ ثانیه‌ای برای درخواست‌های قابل‌فراخوانی استفاده می‌کنند. اگر تکمیل تابع قابل‌فراخوانی بیشتر از ۷۰ ثانیه طول بکشد، کیت توسعه نرم‌افزار کارخواه درخواست را با خطای DEADLINE_EXCEEDED (deadline-exceeded) خاتمه می‌دهد—حتی اگر زمان استراحت طولانی‌تری را در سمت سرور پیکربندی کرده باشید.

برای پشتیبانی از توابع فراخوانی طولانی‌مدت، باید زمان اتمام را در هم سرور و هم کارخواه افزایش دهید:

  1. زمان اتمام عملکرد سمت سرور را افزایش دهید (به تنظیم زمان اتمام و تخصیص حافظه مراجعه کنید).
  2. هنگام پیکربندی مرجع قابل‌فراخوانی در برنامه‌تان، زمان اتمام کارخواه را افزایش دهید:

Swift

let callable = functions.httpsCallable("addMessage")
callable.timeoutInterval = 300  // 300 seconds (default is 70)
let result = try await callable.call(["text": text, "push": true])

Objective-C

FIRHTTPSCallable *callable = [self.functions HTTPSCallableWithName:@"addMessage"];
callable.timeoutInterval = 300;  // 300 seconds (default is 70)
[callable callWithObject:@{@"text": text, @"push": @YES}
              completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) {
  // ...
}];

Web

var addMessage = firebase.functions().httpsCallable('addMessage', {
  timeout: 300000,  // 300 seconds in milliseconds (default is 70000)
});
addMessage({ text: messageText })
  .then((result) => {
    // ...
  });

Web

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

const functions = getFunctions();
const addMessage = httpsCallable(functions, 'addMessage', {
  timeout: 300000,  // 300 seconds in milliseconds (default is 70000)
});
const result = await addMessage({ text: messageText });

Kotlin

val callable = functions.getHttpsCallable("addMessage")
callable.setTimeout(300L, TimeUnit.SECONDS)
val result = callable.call(data).await()

Java

HttpsCallableReference callable = mFunctions.getHttpsCallable("addMessage");
callable.setTimeout(300L, TimeUnit.SECONDS);
Task<HttpsCallableResult> result = callable.call(data);

Dart

final callable = FirebaseFunctions.instance.httpsCallable(
  'addMessage',
  options: HttpsCallableOptions(
    timeout: const Duration(seconds: 300),
  ),
);
final result = await callable.call({
  'text': text,
  'push': true,
});

توصیه‌شده: جلوگیری از سوءاستفاده با App Check

قبل‌از راه‌اندازی برنامه‌تان، باید App Check را فعال کنید تا مطمئن شوید فقط برنامه‌های شما می‌توانند به نقاط پایانی تابع قابل‌فراخوانی شما دسترسی داشته باشند.