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


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

  • פונקציית add message שחשפה כתובת URL שמקבלת ערך טקסט ומשמרת אותו ב-Cloud Firestore.
  • פונקציית 'make uppercase' שמופעל בכתיבה של Cloud Firestore וממירה את הטקסט לאותיות רישיות (אותיות גדולות).

בחרנו ב-Cloud Firestore ובפונקציות JavaScript שמופעל על ידי HTTP לדוגמה הזו, בין היתר כי אפשר לבדוק היטב את הטריגרים האלה ברקע באמצעות Firebase Local Emulator Suite. ערכת הכלים הזו תומכת גם בטריגרים של Realtime Database,‏ PubSub,‏ Auth ו-HTTP callable. אפשר לבדוק באופן אינטראקטיבי סוגים אחרים של טריגרים ברקע, כמו 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. לוחצים על Create project (או על Add Firebase, אם משתמשים בפרויקט Google Cloud קיים).

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

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

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

אחרי שמתקינים את Node.js ואת npm, מתקינים את ה-CLI של Firebase בשיטה המועדפת עליכם. כדי להתקין את ה-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 תוצג בקשה לבחור ל-codebase קיים או לאתחל ולתת שם לבסיס חדש. כשרק מתחילים, מספיק בסיס קוד אחד במיקום ברירת המחדל. בהמשך, ככל שההטמעה תתרחב, כדאי לארגן את הפונקציות בבסיס קוד.
  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.

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

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

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

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

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

באמצעות 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.

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

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

זהו 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, אפשר לבצע גם את הפעולות הבאות: