開始使用:編寫、測試及部署第一個函式


如要開始使用 Cloud Functions,請試著完成這項教學課程,其中會從必要的設定工作開始,逐步說明如何建立、測試及部署兩個相關函式:

  • 「新增訊息」函式,可公開接受文字值的網址,並將該值寫入 Cloud Firestore
  • 「轉換為大寫」函式,會在 Cloud Firestore 寫入時觸發,並將文字轉換為大寫。

我們選擇 Cloud Firestore 和 HTTP 觸發的 JavaScript 函式做為這個範例,部分原因是這些背景觸發程序可透過 Firebase Local Emulator Suite 進行全面測試。這組工具也支援 Realtime Database、PubSub、Auth 和 HTTP 可呼叫觸發條件。其他類型的背景觸發條件 (例如 Remote Config、TestLab 和 Analytics 觸發條件) 都可以使用本頁未說明的工具集以互動方式測試

本教學課程的後續章節會詳細說明建構、測試及部署範例所需的步驟。如果您只想執行程式碼並檢查,請跳至「 查看完整程式碼範例」。

建立 Firebase 專案

  1. Firebase 控制台中,按一下「新增專案」

    • 如要將 Firebase 資源新增至現有 Google Cloud 專案,請輸入專案名稱或從下拉式選單中選取專案。

    • 如要建立專案,請輸入專案名稱。您也可以選擇編輯專案名稱下方顯示的專案 ID。

  2. 如果系統顯示提示,請詳閱並接受 Firebase 條款

  3. 按一下「繼續」

  4. (選用) 為專案設定 Google Analytics,以便使用下列 Firebase 產品,獲得最佳體驗: Firebase A/B TestingCloud MessagingCrashlyticsIn-App MessagingRemote Config (包括個人化)。

    選取現有Google Analytics帳戶或建立新帳戶。如果建立新帳戶,請選取Analytics報表位置,然後接受專案的資料共用設定和Google Analytics條款。

  5. 按一下「建立專案」 (或「新增 Firebase」,如果要在現有的 Google Cloud 專案中新增 Firebase)。

Firebase 會自動為您的 Firebase 專案佈建資源。完成程序後,系統會將您帶往 Firebase 控制台的 Firebase 專案總覽頁面。

設定 Node.js 和 Firebase CLI

您需要 Node.js 環境來編寫函式,並使用 Firebase CLI 將函式部署至 Cloud Functions 執行階段。建議使用 Node Version Manager 安裝 Node.js 和 npm

安裝 Node.js 和 npm 後,請透過偏好的方法安裝 Firebase CLI。如要透過 npm 安裝 CLI,請使用:

npm install -g firebase-tools

這會安裝全域可用的 firebase 指令。如果指令失敗,你可能需要變更 npm 權限。如要更新至最新版的 firebase-tools,請重新執行相同指令。

初始化您的專案

初始化 Firebase SDK for 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 版本。您可以選取其他支援的版本

匯入必要模組並初始化應用程式

完成設定工作後,即可開啟來源目錄,並按照下列各節的說明開始新增程式碼。在這個範例中,您的專案必須使用 Node require 陳述式匯入 Cloud Functions 和 Admin SDK 模組。在 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-functionsfirebase-admin 模組,並初始化 admin 應用程式例項,藉此進行 Cloud Firestore 變更。凡是支援 Admin SDK 的地方 (例如 FCMAuthenticationFirebase Realtime Database),都可以透過 Cloud Functions 整合 Firebase,功能十分強大。

初始化專案時,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() 函式是 HTTP 端點。對端點發出的任何要求,都會產生傳遞至 onRequest() 回呼的 ExpressJS 樣式 RequestResponse 物件。

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

Cloud Firestore 寫入時,系統會執行 makeUppercase() 函式。ref.set 函式會定義要監聽的文件。基於效能考量,請盡可能具體說明。

大括號 (例如 {documentId}) 會將「參數」括起來,這些參數是萬用字元,可將相符資料公開在回呼中。

每當新增訊息時,Cloud Firestore 就會觸發 onCreate() 回呼。

事件導向的函式 (例如 Cloud Firestore 事件) 為非同步函式。回呼函式應傳回 null、物件或 Promise。如果您未傳回任何內容,函式會逾時並發出錯誤信號,然後重試。請參閱「同步、非同步和 Promise」。

模擬函式執行作業

Firebase Local Emulator Suite 可讓您在本機電腦上建構及測試應用程式,不必部署至 Firebase 專案。強烈建議您在開發期間進行本機測試,部分原因是這麼做可降低程式碼錯誤的風險,避免在實際執行環境中產生費用 (例如無限迴圈)。

如要模擬函式,請按照下列步驟操作:

  1. 執行 firebase emulators:start,並檢查 Emulator Suite UI 的網址輸出內容。預設為 localhost:4000,但可能會在本機上的其他通訊埠代管。在瀏覽器中輸入該網址,開啟 Emulator Suite UI

  2. 檢查 firebase emulators:start 指令的輸出內容,找出 HTTP 函式的網址 addMessage()。看起來會類似 http://localhost:5001/MY_PROJECT/us-central1/addMessage,但有以下例外狀況:

    1. MY_PROJECT 會替換為您的專案 ID。
    2. 本機電腦上的通訊埠可能不同。
  3. 在函式網址結尾新增查詢字串 ?text=uppercaseme。如下所示: http://localhost:5001/MY_PROJECT/us-central1/addMessage?text=uppercaseme。 你也可以視需要將「uppercaseme」訊息變更為自訂訊息。

  4. 在瀏覽器的新分頁中開啟網址,即可建立新訊息。

  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
     

    執行這項指令後,Firebase CLI 會輸出所有 HTTP 函式端點的網址。終端機應會顯示類似下列內容的行:

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

    網址包含專案 ID 和 HTTP 函式的區域。雖然您現在不必擔心,但部分 HTTP 生產函式應指定位置,以盡量減少網路延遲。

    如果遇到「無法授權存取專案」等存取錯誤,請嘗試檢查專案別名

  2. 使用 CLI 輸出的 addMessage() 網址,新增文字查詢參數,並在瀏覽器中開啟:

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

    函式會執行,並將瀏覽器重新導向至 Firebase 控制台,前往儲存文字字串的資料庫位置。這個寫入事件會觸發 makeUppercase(),並寫入字串的大寫版本。

部署及執行函式後,您可以在 Google Cloud 控制台中查看記錄。如需刪除開發或正式環境中的函式,請使用 Firebase CLI。

在正式環境中,您可以設定執行個體數量下限和上限,藉此控管費用,並盡可能提升函式效能。如要進一步瞭解這些執行階段選項,請參閱「控管資源調度行為」。

查看完整程式碼範例

以下是已完成的 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,您也可以採取下列做法: