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


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

  • פונקציית add message שחשפה כתובת 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, לוחצים על Add project.

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

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

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

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

  4. (אופציונלי) מגדירים את Google Analytics לפרויקט, וכך כדי ליהנות מחוויה אופטימלית בשימוש בכל אחד ממוצרי Firebase הבאים:

    יש לבחור חשבון קיים חשבון אחד (Google Analytics) או ליצור חשבון חדש.

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

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

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

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

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

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

npm install -g firebase-tools

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

הפעלת הפרויקט

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

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

  1. מריצים את firebase login כדי להתחבר דרך הדפדפן ולאמת את Firebase CLI.
  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 בזמן האתחול בפרויקט שלכם. כדי להוסיף לפרויקט ספריות של צד שלישי, אפשר לשנות את 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) יוצרת אובייקטים מסוג Request ו-Response בסגנון ExpressJS, שמועברים ל-callback‏ onRequest().

פונקציות HTTP הן סינכרוניות (בדומה לפונקציות ניתנות לקריאה), לכן צריך לשלוח תשובה מהר ככל האפשר ולדחות את העבודה באמצעות Cloud Firestore. פונקציית ה-HTTP‏ addMessage() מעבירה ערך טקסט לנקודת הקצה של ה-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 מפעיל את onCreate() להתקשרות חזרה בכל פעם שנוספו הודעות חדשות.

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

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

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. בכרטיסייה Logs אמורים להופיע יומנים חדשים שמציינים שהפונקציות 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.

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

קוד לדוגמה מלא

הנה 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, יכול לבצע גם את הפעולות הבאות: