البدء: كتابة الدوال الأولى واختبارها ونشرها


لبدء استخدام Cloud Functions، يُرجى الاطّلاع على هذا البرنامج التعليمي، الذي يبدأ بمهام الإعداد المطلوبة ويتيح لك إنشاء دالتَين مرتبطتَين بهما واختبارهما ونشرهما:

  • دالة "إضافة رسالة" تعرض عنوان URL يقبل قيمة نصية وتكتبه في Cloud Firestore
  • يشير ذلك المصطلح إلى دالة "إنشاء أحرف كبيرة" التي يتم تشغيلها في Cloud Firestore وتحوِّل النص إلى أحرف كبيرة.

في ما يلي الرمز الكامل الذي يحتوي على الدوال:

Node.js

// The Cloud Functions for Firebase SDK to create Cloud Functions and triggers.
const {logger} = require("firebase-functions");
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

// The Firebase Admin SDK to access Firestore.
const {initializeApp} = require("firebase-admin/app");
const {getFirestore} = require("firebase-admin/firestore");

initializeApp();

// Take the text parameter passed to this HTTP endpoint and insert it into
// Firestore under the path /messages/:documentId/original
exports.addmessage = onRequest(async (req, res) => {
  // Grab the text parameter.
  const original = req.query.text;
  // Push the new message into Firestore using the Firebase Admin SDK.
  const writeResult = await getFirestore()
      .collection("messages")
      .add({original: original});
  // Send back a message that we've successfully written the message
  res.json({result: `Message with ID: ${writeResult.id} added.`});
});

// Listens for new messages added to /messages/:documentId/original
// and saves an uppercased version of the message
// to /messages/:documentId/uppercase
exports.makeuppercase = onDocumentCreated("/messages/{documentId}", (event) => {
  // Grab the current value of what was written to Firestore.
  const original = event.data.data().original;

  // Access the parameter `{documentId}` with `event.params`
  logger.log("Uppercasing", event.params.documentId, original);

  const uppercase = original.toUpperCase();

  // You must return a Promise when performing
  // asynchronous tasks inside a function
  // such as writing to Firestore.
  // Setting an 'uppercase' field in Firestore document returns a Promise.
  return event.data.ref.set({uppercase}, {merge: true});
});

Python

# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import firestore_fn, https_fn

# The Firebase Admin SDK to access Cloud Firestore.
from firebase_admin import initialize_app, firestore
import google.cloud.firestore

app = initialize_app()


@https_fn.on_request()
def addmessage(req: https_fn.Request) -> https_fn.Response:
    """Take the text parameter passed to this HTTP endpoint and insert it into
    a new document in the messages collection."""
    # Grab the text parameter.
    original = req.args.get("text")
    if original is None:
        return https_fn.Response("No text parameter provided", status=400)

    firestore_client: google.cloud.firestore.Client = firestore.client()

    # Push the new message into Cloud Firestore using the Firebase Admin SDK.
    _, doc_ref = firestore_client.collection("messages").add({"original": original})

    # Send back a message that we've successfully written the message
    return https_fn.Response(f"Message with ID {doc_ref.id} added.")


@firestore_fn.on_document_created(document="messages/{pushId}")
def makeuppercase(event: firestore_fn.Event[firestore_fn.DocumentSnapshot | None]) -> None:
    """Listens for new documents to be added to /messages. If the document has
    an "original" field, creates an "uppercase" field containg the contents of
    "original" in upper case."""

    # Get the value of "original" if it exists.
    if event.data is None:
        return
    try:
        original = event.data.get("original")
    except KeyError:
        # No "original" field, so do nothing.
        return

    # Set the "uppercase" field.
    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    event.data.reference.update({"uppercase": upper})

لمحة عن هذا الدليل التوجيهي

لقد اخترنا الدوال التي يتم تشغيلها في Cloud Firestore والدالّة التي يتم تشغيلها عبر HTTP لهذه العينة جزئيًا لأنّه يمكن اختبار المشغِّلات في الخلفية بدقة من خلال مجموعة أدوات المحاكاة المحلية من Firebase. تتوافق مجموعة الأدوات هذه أيضًا مع عوامل التشغيل القابلة للاستدعاء في الوقت الفعلي، وCloud Storage وPubSub وAuth وHTTP. يمكن اختبار الأنواع الأخرى من المشغِّلات في الخلفية، مثل المشغِّلات عن بُعد وTestLab، بشكل تفاعلي باستخدام مجموعات أدوات غير موضحة في هذه الصفحة.

توضح الأقسام التالية من هذا البرنامج التعليمي بالتفصيل الخطوات المطلوبة لإنشاء النموذج واختباره ونشره.

إنشاء مشروع Firebase

  1. في وحدة تحكُّم Firebase، انقر على إضافة مشروع.

    • لإضافة موارد Firebase إلى مشروع حالي على Google Cloud، أدخِل اسم مشروعه أو اختَره من القائمة المنسدلة.

    • لإنشاء مشروع جديد، أدخِل اسم المشروع المطلوب. يمكنك أيضًا تعديل رقم تعريف المشروع المعروض أسفل اسم المشروع اختياريًا.

  2. راجِع بنود Firebase واقبلها إذا طُلب منك ذلك.

  3. انقر على متابعة.

  4. (اختياري) يمكنك إعداد "إحصاءات Google" لمشروعك، ما يتيح لك الحصول على تجربة مثالية باستخدام أي من منتجات Firebase التالية:

    اختَر حسابًا حاليًا على "إحصاءات Google" أو أنشئ حسابًا جديدًا.

    إذا أنشأت حسابًا جديدًا، اختَر موقع إعداد تقارير "إحصاءات Google"، ثم اقبل إعدادات مشاركة البيانات وبنود "إحصاءات Google" لمشروعك.

  5. انقر على إنشاء مشروع (أو إضافة Firebase إذا كنت تستخدم مشروعًا حاليًا على Google Cloud).

يوفّر Firebase تلقائيًا الموارد لمشروعك على Firebase. عند اكتمال العملية، سيتم نقلك إلى صفحة النظرة العامة لمشروع Firebase في "وحدة تحكُّم Firebase".

إعداد البيئة وواجهة سطر الأوامر في Firebase

Node.js

ستحتاج إلى بيئة Node.js لكتابة الدوال، وستحتاج إلى واجهة سطر الأوامر في Firebase لنشر الوظائف في وقت تشغيل دوال Cloud. لتثبيت Node.js وnpm، يُنصح باستخدام مدير إصدارات العقدة.

بعد تثبيت Node.js وnpm، يمكنك تثبيت واجهة سطر الأوامر في Firebase من خلال طريقتك المفضّلة. لتثبيت واجهة سطر الأوامر من خلال npm، استخدم:

npm install -g firebase-tools

يؤدي هذا إلى تثبيت أمر firebase المتاح عالميًا. إذا فشل الأمر، قد تحتاج إلى تغيير أذونات npm. للتحديث إلى آخر إصدار من firebase-tools، أعِد تشغيل الأمر نفسه.

Python

ستحتاج إلى بيئة Python لكتابة الدوال، وستحتاج إلى واجهة سطر الأوامر في Firebase لنشر الوظائف في وقت تشغيل دوال Cloud. ننصح باستخدام venv لفصل التبعيات. الإصداران 3.10 و3.11 من Python متوافقان.

بعد تثبيت لغة Python، ثبِّت واجهة سطر الأوامر في Firebase من خلال طريقتك المفضّلة.

إعداد مشروعك

عند إعداد حزمة تطوير البرامج (SDK) لمنصّة Firebase لوظائف السحابة الإلكترونية، يمكنك إنشاء مشروع فارغ يحتوي على اعتماديات وبعض العيّنة الأدنى من الرموز البرمجية. إذا كنت تستخدم Node.js، يمكنك اختيار نوع النص البرمجي أو JavaScript لإنشاء الدوال. لأغراض هذا البرنامج التعليمي، ستحتاج أيضًا إلى تهيئة Cloud Firestore.

لتهيئة مشروعك:

  1. شغِّل firebase login لتسجيل الدخول من خلال المتصفّح ومصادقة واجهة سطر الأوامر في Firebase.
  2. انتقِل إلى دليل مشروع Firebase.
  3. تشغيل firebase init firestore في هذا البرنامج التعليمي، يمكنك قبول القيم التلقائية عندما يُطلب منك إدخال قواعد Firestore وملفات الفهرسة. إذا لم تكن قد استخدمت Cloud Firestore في هذا المشروع حتى الآن، عليك أيضًا اختيار وضع البدء والموقع الجغرافي لـ Firestore كما هو موضّح في بدء استخدام Cloud Firestore.
  4. تشغيل firebase init functions يطالبك واجهة سطر الأوامر باختيار قاعدة أكواد حالية أو تهيئة قاعدة جديدة وتسميتها. عندما تبدأ للتو، يكفي توفّر قاعدة رموز برمجية واحدة في الموقع التلقائي. في وقت لاحق، مع توسيع عملية التنفيذ، قد تريد تنظيم الدوال في قواعد الرموز.
  5. يمنحك واجهة سطر الأوامر الخيارات التالية للحصول على دعم اللغات:

    • JavaScript
    • TypeScript
    • Python

    في هذا الدليل التعليمي، اختَر JavaScript أو Python. وبالنسبة إلى التأليف في TypeScript، يُرجى الاطّلاع على كتابة الدوال باستخدام TypeScript.

  6. يمنحك واجهة سطر الأوامر خيارًا لتثبيت التبعيات. من الآمن الرفض إذا كنت تريد إدارة التبعيات بطريقة أخرى.

بعد اكتمال هذه الأوامر بنجاح، سيبدو هيكل مشروعك كما يلي:

Node.js

myproject
+- .firebaserc    # Hidden file that helps you quickly switch between
|                 # projects with `firebase use`
|
+- firebase.json  # Describes properties for your project
|
+- functions/     # Directory containing all your functions code
      |
      +- .eslintrc.json  # Optional file containing rules for JavaScript linting.
      |
      +- package.json  # npm package file describing your Cloud Functions code
      |
      +- index.js      # Main source file for your Cloud Functions code
      |
      +- node_modules/ # Directory where your dependencies (declared in
                        # package.json) are installed

بالنسبة إلى Node.js، يحتوي ملف package.json الذي تم إنشاؤه أثناء الإعداد على مفتاح مهم: "engines": {"node": "18"}. يحدّد ذلك إصدار Node.js لكتابة الدوال ونشرها. يمكنك اختيار إصدارات أخرى متوافقة.

Python

myproject
+- .firebaserc    # Hidden file that helps you quickly switch between
|                 # projects with `firebase use`
|
+- firebase.json  # Describes properties for your project
|
+- functions/     # Directory containing all your functions code
      |
      +- main.py      # Main source file for your Cloud Functions code
      |
      +- requirements.txt  #  List of the project's modules and packages 
      |
      +- venv/ # Directory where your dependencies are installed

استيراد الوحدات المطلوبة وإعداد تطبيق

بعد الانتهاء من مهام الإعداد، يمكنك فتح الدليل المصدر والبدء في إضافة الرمز كما هو مُوضَّح في الأقسام التالية. في هذا النموذج، يجب أن يستورد مشروعك وحدتَي Cloud Functions وAdmin SDK. أضف سطورًا مثل ما يلي إلى ملف المصدر:

Node.js

// The Cloud Functions for Firebase SDK to create Cloud Functions and triggers.
const {logger} = require("firebase-functions");
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

// The Firebase Admin SDK to access Firestore.
const {initializeApp} = require("firebase-admin/app");
const {getFirestore} = require("firebase-admin/firestore");

initializeApp();

Python

# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import firestore_fn, https_fn

# The Firebase Admin SDK to access Cloud Firestore.
from firebase_admin import initialize_app, firestore
import google.cloud.firestore

app = initialize_app()

تُحمِّل هذه الأسطر الوحدات المطلوبة وتضبط مثيل تطبيق admin الذي يمكن إجراء تغييرات Cloud Firestore منه. في أي مكان يتوفر دعم SDK للمشرف، كما هو الحال بالنسبة إلى خدمة "المراسلة عبر السحابة الإلكترونية من Firebase" والمصادقة وقاعدة بيانات Firebase في الوقت الفعلي، فإنه يوفر طريقة فعّالة لدمج Firebase باستخدام وظائف السحابة الإلكترونية.

يعمل واجهة سطر الأوامر في Firebase تلقائيًا على تثبيت وحدتَي SDK لمشرفي Firebase وFirebase SDK for Cloud Functions عند إعداد مشروعك. لمزيد من المعلومات حول إضافة مكتبات تابعة لجهات خارجية إلى مشروعك، يمكنك الاطّلاع على تبعيات الأسماء المعرِّفة.

إضافة الدالة "إضافة رسالة"

بالنسبة إلى دالة "إضافة رسالة"، أضِف هذه الأسطر إلى ملف المصدر:

Node.js

// Take the text parameter passed to this HTTP endpoint and insert it into
// Firestore under the path /messages/:documentId/original
exports.addmessage = onRequest(async (req, res) => {
  // Grab the text parameter.
  const original = req.query.text;
  // Push the new message into Firestore using the Firebase Admin SDK.
  const writeResult = await getFirestore()
      .collection("messages")
      .add({original: original});
  // Send back a message that we've successfully written the message
  res.json({result: `Message with ID: ${writeResult.id} added.`});
});

Python

@https_fn.on_request()
def addmessage(req: https_fn.Request) -> https_fn.Response:
    """Take the text parameter passed to this HTTP endpoint and insert it into
    a new document in the messages collection."""
    # Grab the text parameter.
    original = req.args.get("text")
    if original is None:
        return https_fn.Response("No text parameter provided", status=400)

    firestore_client: google.cloud.firestore.Client = firestore.client()

    # Push the new message into Cloud Firestore using the Firebase Admin SDK.
    _, doc_ref = firestore_client.collection("messages").add({"original": original})

    # Send back a message that we've successfully written the message
    return https_fn.Response(f"Message with ID {doc_ref.id} added.")

دالة "إضافة رسالة" هي نقطة نهاية HTTP. ينتج عن أي طلب إلى نقطة النهاية كائنات الطلب والاستجابة التي يتم تمريرها إلى معالج الطلبات للنظام الأساسي (onRequest() أو on_request).

تكون دوال HTTP متزامنة (على غرار الدوال القابلة للاستدعاء)، لذا يجب إرسال استجابة في أسرع وقت ممكن وتأجيل العمل باستخدام Cloud Firestore. تمرِّر دالة HTTP "إضافة رسالة" قيمة نصية إلى نقطة نهاية HTTP وتدرجها في قاعدة البيانات ضمن المسار /messages/:documentId/original.

إضافة الدالة "جعل الأحرف الكبيرة"

بالنسبة إلى دالة "جعل الأحرف الكبيرة"، أضف هذه الأسطر إلى ملف المصدر:

Node.js

// Listens for new messages added to /messages/:documentId/original
// and saves an uppercased version of the message
// to /messages/:documentId/uppercase
exports.makeuppercase = onDocumentCreated("/messages/{documentId}", (event) => {
  // Grab the current value of what was written to Firestore.
  const original = event.data.data().original;

  // Access the parameter `{documentId}` with `event.params`
  logger.log("Uppercasing", event.params.documentId, original);

  const uppercase = original.toUpperCase();

  // You must return a Promise when performing
  // asynchronous tasks inside a function
  // such as writing to Firestore.
  // Setting an 'uppercase' field in Firestore document returns a Promise.
  return event.data.ref.set({uppercase}, {merge: true});
});

Python

@firestore_fn.on_document_created(document="messages/{pushId}")
def makeuppercase(event: firestore_fn.Event[firestore_fn.DocumentSnapshot | None]) -> None:
    """Listens for new documents to be added to /messages. If the document has
    an "original" field, creates an "uppercase" field containg the contents of
    "original" in upper case."""

    # Get the value of "original" if it exists.
    if event.data is None:
        return
    try:
        original = event.data.get("original")
    except KeyError:
        # No "original" field, so do nothing.
        return

    # Set the "uppercase" field.
    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    event.data.reference.update({"uppercase": upper})

يتم تنفيذ الدالة "make summary" عند كتابة Cloud Firestore إلى، لتحديد المستند الذي سيستمع إليه. لأسباب تتعلق بالأداء، يجب أن تكون محددًا قدر الإمكان.

الأقواس، مثل {documentId}، المحيطة بـ "المَعلمات"، وهي أحرف بدل تعرض البيانات المتطابقة في معاودة الاتصال. تؤدي Cloud Firestore إلى معاودة الاتصال عند إضافة رسائل جديدة.

في Node.js، تكون الدوال المستندة إلى الأحداث، مثل أحداث Cloud Firestore، غير متزامنة. يجب أن تعرض دالة الاستدعاء إما null أو كائن أو وعد. إذا لم يتم عرض أي شيء، تنتهي المهلة المحددة للدالة، ما يشير إلى وجود خطأ، ثم تتم إعادة المحاولة. يمكنك الاطّلاع على القسم المزامنة غير المتزامنة والوعود.

محاكاة تنفيذ الدوال

تتيح لك حزمة أدوات المحاكاة المحلية من Firebase إنشاء تطبيقات واختبارها على جهازك المحلي بدلاً من نشرها في مشروع على Firebase. وننصح بشدة بإجراء اختبار محلي أثناء التطوير، ويرجع ذلك جزئيًا إلى أنه يقلل من مخاطر أخطاء الترميز التي قد تترتّب عنها تكاليف في بيئة إنتاج (على سبيل المثال، التكرار اللانهائي).

لمحاكاة الدوال:

  1. شغِّل firebase emulators:start وتحقَّق من عنوان URL الخاص بواجهة المستخدم في Emulator Suite. ويتم ضبطها تلقائيًا على localhost:4000، ولكن قد تتم استضافتها على منفذ مختلف على جهازك. أدخِل عنوان URL هذا في المتصفّح لفتح واجهة مستخدم Emulator Suite.

  2. تحقَّق من ناتج الأمر firebase emulators:start للحصول على عنوان URL الخاص بدالة HTTP. سيبدو مشابهًا للرمز http://localhost:5001/MY_PROJECT/us-central1/addMessage، باستثناء ما يلي:

    1. سيتم استبدال MY_PROJECT برقم تعريف مشروعك.
    2. قد يختلف المنفذ على جهازك المحلي.
  3. أضِف سلسلة طلب البحث ?text=uppercaseme إلى نهاية عنوان URL للدالة. من المفترض أن يبدو العرض على النحو التالي: http://localhost:5001/MY_PROJECT/us-central1/addMessage?text=uppercaseme. يمكنك اختياريًا تغيير الرسالة "كبير الأحرف" إلى رسالة مخصّصة.

  4. يمكنك إنشاء رسالة جديدة من خلال فتح عنوان URL في علامة تبويب جديدة في المتصفّح.

  5. عرض تأثيرات الدوال في واجهة مستخدم Emulator Suite:

    1. في علامة التبويب السجلات، من المفترض أن تظهر لك سجلات جديدة تشير إلى إتمام دوال HTTP بنجاح:

      i functions: Beginning execution of "addMessage"

      i functions: Beginning execution of "makeUppercase"

    2. في علامة التبويب Firestore، من المفترض أن يظهر لك مستند يحتوي على رسالتك الأصلية، بالإضافة إلى النسخة الكبيرة من رسالتك (إذا كانت كتابة الرسالة "كبيرة" في الأصل، ستظهر لك عبارة "أحرف كبيرة").

نشر الدوال في بيئة إنتاج

بعد أن تعمل الوظائف على النحو المطلوب في المحاكي، يمكنك مواصلة نشرها واختبارها وتشغيلها في بيئة الإنتاج. ضع في اعتبارك أنّ مشروعك لنشره في مرحلة الإنتاج يجب أن يكون ضمن خطة أسعار Blaze. يُرجى الاطّلاع على أسعار Cloud Functions.

لإكمال البرنامج التعليمي، انشر الدوال ثم نفذها.

  1. نفِّذ الأمر التالي لنشر الدوال:

     firebase deploy --only functions
     

    بعد تشغيل هذا الأمر، يُخرج واجهة سطر الأوامر في Firebase عنوان URL لأي نقاط نهاية لدوال HTTP. في الوحدة الطرفية، من المفترض أن يظهر خط مثل ما يلي:

    Function URL (addMessage): https://us-central1-MY_PROJECT.cloudfunctions.net/addMessage
    

    يحتوي عنوان URL على رقم تعريف مشروعك بالإضافة إلى منطقة لدالة HTTP. ليس عليك القلق الآن، ولكن يجب أن تحدّد بعض دوال HTTP للإنتاج موقعًا جغرافيًا لتقليل وقت استجابة الشبكة.

    في حال واجهتك أخطاء في الوصول مثل "تعذّرت مصادقة الوصول إلى المشروع"، جرِّب التحقُّق من الاسم المستعار للمشروع.

  2. باستخدام إخراج عنوان URL من خلال واجهة سطر الأوامر، أضِف مَعلمة طلب بحث نصي، ثم افتحها في متصفّح باتّباع الخطوات التالية:

    https://us-central1-MY_PROJECT.cloudfunctions.net/addMessage?text=uppercasemetoo
    

    تنفِّذ الدالة المتصفّح وتعيد توجيهه إلى وحدة تحكُّم Firebase في موقع قاعدة البيانات الذي يتم فيه تخزين السلسلة النصية. يؤدي حدث "الكتابة" هذا إلى تشغيل الدالة "make uppercase"، التي تكتب نسخة كبيرة من السلسلة.

بعد نشر الوظائف وتنفيذها، يمكنك عرض السجلات في وحدة تحكُّم Google Cloud. إذا كنت تريد حذف الدوال في مرحلة التطوير أو الإنتاج، استخدِم واجهة سطر الأوامر في Firebase.

في الإنتاج، قد ترغب في تحسين أداء الوظائف والتحكم في التكاليف من خلال تعيين حد أدنى وأقصى لعدد الحالات التي يتم تشغيلها. يُرجى الاطّلاع على التحكّم في سلوك الضبط للحصول على مزيد من المعلومات حول خيارات بيئة التشغيل هذه.

الخطوات اللاحقة

في هذا المستند، يمكنك معرفة المزيد حول كيفية إدارة الدوال لـ Cloud Functions بالإضافة إلى كيفية التعامل مع جميع أنواع الأحداث المتوافقة مع Cloud Functions.

لمعرفة المزيد عن دوال السحابة، يمكنك أيضًا إجراء ما يلي: