תחילת העבודה: כתיבה, בדיקה ופריסה של הפונקציות הראשונות


כדי להתחיל להשתמש ב-Cloud Functions, אפשר לעיין במדריך הזה. הוא מתחיל במשימות ההגדרה הנדרשות וממשיך ליצירה, לבדיקה ולפריסה של שתי פונקציות קשורות:

  • פונקציה של 'הוספת הודעה' שחושפת כתובת URL שמקבלת ערך טקסט וכותבת אותו אל Cloud Firestore.
  • פונקציה של 'הפיכה לאותיות רישיות' שמופעלת על Cloud Firestore כתיבה וממירה את הטקסט לאותיות רישיות.

בחרנו ב-Cloud Firestore ובפונקציות JavaScript שמופעלות על ידי HTTP לדוגמה הזו, בין היתר כי אפשר לבדוק ביסודיות את הטריגרים האלה ברקע באמצעות Firebase Local Emulator Suite. ערכת הכלים הזו תומכת גם ב-Realtime Database, ב-PubSub, ב-Auth ובטריגרים שניתן להפעיל באמצעות HTTP. אפשר לבדוק באופן אינטראקטיבי טריגרים אחרים מסוגים שונים שפועלים ברקע, כמו Remote Config, TestLab וטריגרים של Analytics, באמצעות ערכות כלים שלא מתוארות בדף הזה.

בקטעים הבאים של המדריך הזה מפורטים השלבים הנדרשים לבנייה, לבדיקה ולפריסה של הדוגמה. אם אתם מעדיפים להריץ את הקוד ולבדוק אותו, אתם יכולים לדלג אל בדיקת קוד לדוגמה מלא.

יצירת פרויקט Firebase

  1. במסוף Firebase, לוחצים על הוספת פרויקט.

    • כדי להוסיף משאבי Firebase לפרויקט קיים Google Cloud צריך להזין את שם הפרויקט או לבחור אותו מהתפריט הנפתח.

    • כדי ליצור פרויקט חדש, מזינים שם לפרויקט. אפשר גם לערוך את מזהה הפרויקט שמוצג מתחת לשם הפרויקט.

  2. אם תופיע בקשה, תצטרכו לקרוא את התנאים של Firebase ולאשר אותם.

  3. לוחצים על המשך.

  4. (אופציונלי) מגדירים את Google Analytics לפרויקט, כדי ליהנות מחוויה אופטימלית באמצעות המוצרים הבאים של Firebase:‏ Firebase A/B Testing,‏ Cloud Messaging,‏ Crashlytics,‏ In-App Messaging ו-Remote Config (כולל התאמה אישית).

    בוחרים חשבון Google Analytics קיים או יוצרים חשבון חדש. אם יוצרים חשבון חדש, בוחרים את Analytics מיקום הדיווח, ואז מאשרים את הגדרות שיתוף הנתונים ואת Google Analytics התנאים של הפרויקט.

  5. לוחצים על יצירת פרויקט (או על הוספת Firebase, אם מוסיפים את Firebase לפרויקט קיים של Google Cloud).

מערכת Firebase מקצה באופן אוטומטי משאבים לפרויקט Firebase. בסיום התהליך, תועברו לדף הסקירה הכללית של פרויקט Firebase בFirebase מסוף.

הגדרת Node.js ו-Firebase CLI

כדי לכתוב פונקציות, תצטרכו סביבת Node.js, וכדי לפרוס פונקציות בסביבת זמן הריצה Cloud Functions, תצטרכו את Firebase CLI. מומלץ להתקין את Node.js ואת npm באמצעות Node Version Manager.

אחרי שמתקינים את Node.js ואת npm, מתקינים את Firebase CLI בשיטה המועדפת. כדי להתקין את ה-CLI באמצעות npm, משתמשים בפקודה:

npm install -g firebase-tools

הפעולה הזו מתקינה את הפקודה firebase שזמינה בכל העולם. אם הפקודה נכשלת, יכול להיות שתצטרכו לשנות את ההרשאות של npm. כדי לעדכן לגרסה העדכנית של firebase-tools, מריצים מחדש את אותה פקודה.

אתחול הפרויקט

כשמפעילים את Firebase SDK ל-Cloud Functions, יוצרים פרויקט ריק שמכיל תלות וקוד לדוגמה מינימלי, ובוחרים אם להשתמש ב-TypeScript או ב-JavaScript כדי ליצור פונקציות. לצורך המדריך הזה, תצטרכו גם לאתחל את Cloud Firestore.

כדי לאתחל את הפרויקט:

  1. מריצים את הפקודה firebase login כדי להיכנס דרך הדפדפן ולאמת את CLI של Firebase.

  2. עוברים לספריית הפרויקט ב-Firebase.

  3. מריצים את firebase init firestore. במדריך הזה, אפשר לאשר את ערכי ברירת המחדל כשמוצגת בקשה לכללי Firestore ולקובצי אינדקס. אם עדיין לא השתמשתם ב-Cloud Firestore בפרויקט הזה, תצטרכו גם לבחור מצב התחלה ומיקום ל-Firestore, כמו שמתואר במאמר תחילת העבודה עם Cloud Firestore.

  4. מריצים את firebase init functions. ב-CLI מוצגת הנחיה לבחור בסיס קוד קיים או לאתחל בסיס קוד חדש ולתת לו שם. כשמתחילים, מספיק בסיס קוד יחיד במיקום ברירת המחדל. בהמשך, כשההטמעה מתרחבת, כדאי לארגן פונקציות בבסיסי קוד.

  5. ה-CLI מספק את האפשרויות הבאות לתמיכה בשפה:

    במדריך הזה, בוחרים באפשרות JavaScript.

  6. ה-CLI מאפשר להתקין יחסי תלות באמצעות npm. אפשר לסרב אם רוצים לנהל את התלות בדרך אחרת, אבל אם מסרבים צריך להריץ את הפקודה npm install לפני שמדמים או פורסים את הפונקציות.

אחרי שהפקודות האלה יסתיימו בהצלחה, מבנה הפרויקט ייראה כך:

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

קובץ package.json שנוצר במהלך האתחול מכיל מפתח חשוב: "engines": {"node": "16"}. כאן מציינים את גרסת Node.js לכתיבה ולפריסה של פונקציות. אפשר לבחור גרסאות נתמכות אחרות.

ייבוא המודולים הנדרשים והפעלת אפליקציה

אחרי שמסיימים את משימות ההגדרה, אפשר לפתוח את ספריית המקור ולהתחיל להוסיף קוד כמו שמתואר בקטעים הבאים. בדוגמה הזו, צריך לייבא לפרויקט את המודולים Cloud Functions ו-Admin SDK באמצעות הצהרות Node require. מוסיפים לקובץ index.js שורות כמו אלה:

// The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
const functions = require('firebase-functions/v1');

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

השורות האלה טוענות את המודולים firebase-functions ו-firebase-admin, ומאתחלות מופע של אפליקציית admin שממנו אפשר לבצע שינויים ב-Cloud Firestore. בכל מקום שבו יש תמיכה ב-Admin SDK, כמו ב-FCM, Authentication ו-Firebase Realtime Database, הוא מספק דרך יעילה לשילוב של Firebase באמצעות Cloud Functions.

ממשק Firebase CLI מתקין באופן אוטומטי את Firebase ואת Firebase SDK עבור מודולי Cloud Functions Node כשמפעילים את הפרויקט. כדי להוסיף ספריות של צד שלישי לפרויקט, אפשר לשנות את package.json ולהריץ את npm install. מידע נוסף זמין במאמר בנושא טיפול בתלות.

הוספת הפונקציה addMessage()

בפונקציה addMessage(), מוסיפים את השורות האלה ל-index.js:

// Take the text parameter passed to this HTTP endpoint and insert it into
// Firestore under the path /messages/:documentId/original
exports.addMessage = functions.https.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 admin
    .firestore()
    .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.` });
});

הפונקציה addMessage() היא נקודת קצה (endpoint) של HTTP. כל בקשה לנקודת הקצה (endpoint) מביאה ליצירת אובייקטים של בקשה ותגובה בסגנון ExpressJS שמועברים לקריאה החוזרת (callback) של onRequest().

פונקציות HTTP הן סינכרוניות (בדומה לפונקציות שאפשר להפעיל), ולכן צריך לשלוח תגובה במהירות האפשרית ולדחות עבודה באמצעות Cloud Firestore. הפונקציה addMessage() HTTP מעבירה ערך טקסט לנקודת הקצה של HTTP ומוסיפה אותו למסד הנתונים בנתיב /messages/:documentId/original.

הוספת הפונקציה makeUppercase()

בפונקציה makeUppercase(), מוסיפים את השורות האלה ל-index.js:

// Listens for new messages added to /messages/:documentId/original and creates an
// uppercase version of the message to /messages/:documentId/uppercase
exports.makeUppercase = functions.firestore
  .document("/messages/{documentId}")
  .onCreate((snap, context) => {
    // Grab the current value of what was written to Firestore.
    const original = snap.data().original;

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

    const uppercase = original.toUpperCase();

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

הפונקציה makeUppercase() מופעלת כשכותבים ל-Cloud Firestore. הפונקציה ref.set מגדירה את המסמך להאזנה. מטעמי ביצועים, חשוב להיות כמה שיותר ספציפיים.

סוגריים מסולסלים – לדוגמה, {documentId} – מקיפים את הפרמטרים, תווים כלליים שחושפים את הנתונים התואמים שלהם בקריאה החוזרת.

Cloud Firestore מפעיל את הקריאה החוזרת (callback) של onCreate() בכל פעם שמוסיפים הודעות חדשות.

פונקציות מבוססות-אירועים, כמו אירועי Cloud Firestore, הן אסינכרוניות. פונקציית ההתקשרות חזרה צריכה להחזיר null, אובייקט או Promise. אם לא מחזירים כלום, הפונקציה מפסיקה לפעול בגלל חריגה של זמן קצוב לתפוגה, מה שמצביע על שגיאה, והיא מנסה שוב. מידע נוסף על סנכרון, אסינכרון והבטחות

הדמיית ההפעלה של הפונקציות

Firebase Local Emulator Suite מאפשר לכם ליצור ולבדוק אפליקציות במחשב המקומי במקום לפרוס אותן בפרויקט Firebase. מומלץ מאוד לבצע בדיקות מקומיות במהלך הפיתוח, בין היתר כדי להקטין את הסיכון לשגיאות בקוד שעלולות לגרום לעלויות בסביבת ייצור (לדוגמה, לולאה אינסופית).

כדי לבצע אמולציה של הפונקציות:

  1. מריצים את הפקודה firebase emulators:start ובודקים את הפלט של כתובת ה-URL של Emulator Suite UI. ברירת המחדל היא localhost:4000, אבל יכול להיות שהיא מתארחת ביציאה אחרת במחשב. מזינים את כתובת ה-URL בדפדפן כדי לפתוח את Emulator Suite UI.

  2. בודקים את הפלט של הפקודה firebase emulators:start בשביל כתובת ה-URL של פונקציית ה-HTTP addMessage(). הוא ייראה דומה ל-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. אופציונלי: אפשר לשנות את ההודעה 'uppercaseme' להודעה מותאמת אישית.

  4. יוצרים הודעה חדשה על ידי פתיחת כתובת ה-URL בכרטיסייה חדשה בדפדפן.

  5. אפשר לראות את ההשפעות של הפונקציות ב-Emulator Suite UI:

    1. בכרטיסייה יומנים אמורים להופיע יומנים חדשים שמציינים שהפונקציות addMessage() ו-makeUppercase() הופעלו:

      i functions: Beginning execution of "addMessage"

      i functions: Beginning execution of "makeUppercase"

    2. בכרטיסייה Firestore אמור להופיע מסמך שמכיל את ההודעה המקורית שלכם, וגם את הגרסה של ההודעה באותיות רישיות (אם ההודעה המקורית הייתה uppercaseme, תופיע ההודעה UPPERCASEME).

פריסת פונקציות בסביבת ייצור

אחרי שמוודאים שהפונקציות פועלות כמו שרוצים באמולטור, אפשר להמשיך לפריסה, לבדיקה ולהרצה שלהן בסביבת הייצור. חשוב לזכור: כדי לפרוס לסביבת זמן הריצה Node.js 14, הפרויקט צריך להיות בתוכנית התמחור Blaze. מידע על התמחור של Cloud Functions

כדי להשלים את המדריך, פורסים את הפונקציות ואז מריצים את addMessage() כדי להפעיל את makeUppercase().

  1. מריצים את הפקודה הבאה כדי לפרוס את הפונקציות:

     firebase deploy --only functions
     

    אחרי שמריצים את הפקודה הזו, ה-CLI של Firebase מציג את כתובת ה-URL של כל נקודות הקצה של פונקציות HTTP. במסוף אמורה להופיע שורה כמו זו:

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

    כתובת ה-URL מכילה את מזהה הפרויקט שלכם ואזור לפונקציית ה-HTTP. לא צריך לדאוג לגבי זה עכשיו, אבל בפונקציות מסוימות של HTTP בייצור צריך לציין מיקום כדי למזער את זמן האחזור ברשת.

    אם נתקלתם בשגיאות גישה כמו "לא ניתן לאשר גישה לפרויקט", נסו לבדוק את הכינויים של הפרויקט.

  2. משתמשים בכתובת ה-URL addMessage() שמופקת על ידי ה-CLI, מוסיפים פרמטר של שאילתת טקסט ופותחים אותה בדפדפן:

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

    הפונקציה מופעלת ומפנה את הדפדפן למסוף Firebase במיקום של מסד הנתונים שבו מאוחסן מחרוזת הטקסט. אירוע הכתיבה הזה מפעיל את makeUppercase(), שכותב גרסה באותיות רישיות של המחרוזת.

אחרי פריסה והפעלה של פונקציות, אפשר לראות את היומנים במסוף Google Cloud. אם אתם צריכים למחוק פונקציות שנמצאות בפיתוח או בייצור, אתם יכולים להשתמש ב-CLI של Firebase.

בסביבת ייצור, כדאי להגדיר מספר מינימלי ומקסימלי של מופעים להפעלה כדי לבצע אופטימיזציה של ביצועי הפונקציה ולשלוט בעלויות. מידע נוסף על אפשרויות זמן הריצה האלה מופיע במאמר בנושא שליטה בהתנהגות של שינוי גודל.

בדיקת קוד לדוגמה מלא

זוהי functions/index.jsהפונקציה המלאה שכוללת את הפונקציות addMessage() ו-makeUppercase(). הפונקציות האלה מאפשרות להעביר פרמטר לנקודת קצה של HTTP שכותבת ערך ל-Cloud Firestore, ואז לבצע טרנספורמציה על הערך על ידי המרת כל התווים במחרוזת לאותיות רישיות.

// The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
const functions = require('firebase-functions/v1');

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

// Take the text parameter passed to this HTTP endpoint and insert it into
// Firestore under the path /messages/:documentId/original
exports.addMessage = functions.https.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 admin
    .firestore()
    .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 creates an
// uppercase version of the message to /messages/:documentId/uppercase
exports.makeUppercase = functions.firestore
  .document("/messages/{documentId}")
  .onCreate((snap, context) => {
    // Grab the current value of what was written to Firestore.
    const original = snap.data().original;

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

    const uppercase = original.toUpperCase();

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

השלבים הבאים

במסמכי התיעוד האלה אפשר לקרוא מידע נוסף על ניהול פונקציות ב-Cloud Functions ועל טיפול בכל סוגי האירועים שנתמכים ב-Cloud Functions.

כדי לקבל מידע נוסף על Cloud Functions, אפשר גם לבצע את הפעולות הבאות: