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


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

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

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

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

建立 Firebase 專案

Firebase 或 Cloud 新手

如果您是 Firebase 或 Google Cloud 的新手,請按照下列步驟操作。
如要建立全新的 Firebase 專案 (和底層的 Google Cloud 專案),也可以按照下列步驟操作。

  1. 登入 Firebase 控制台
  2. 按一下按鈕,建立新的 Firebase 專案。
  3. 在文字欄位中輸入專案名稱

    如果您是 Google Cloud 機構的成員,可以選擇要在哪個資料夾中建立專案。

  4. 如果系統提示,請詳閱並接受 Firebase 條款,然後按一下「繼續」
  5. (選用)Firebase 控制台中啟用 AI 輔助功能 (稱為「Gemini in Firebase」),協助您開始使用服務及簡化開發程序。
  6. (選用) 為專案設定 Google Analytics, 即可透過下列 Firebase 產品獲得最佳體驗: Firebase A/B TestingCloud MessagingCrashlyticsIn-App MessagingRemote Config (包括 個人化)。

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

  7. 按一下「建立專案」

Firebase 會建立專案、提供一些初始資源,並啟用重要的 API。完成後,系統會將您帶往 Firebase 控制台的 Firebase 專案總覽頁面。

現有 Cloud 專案

如要開始使用 Firebase 搭配現有Google Cloud專案,請按照下列步驟操作。進一步瞭解如何將 Firebase 新增至現有的 Google Cloud 專案

  1. 使用可存取現有 Google Cloud 專案的帳戶登入 Firebase 控制台
  2. 按一下按鈕,建立新的 Firebase 專案。
  3. 在頁面底部點選「將 Firebase 新增到 Google Cloud 專案」
  4. 在文字欄位中,開始輸入現有專案的專案名稱,然後從顯示的清單中選取專案。
  5. 按一下「開啟專案」
  6. 如果系統提示,請詳閱並接受 Firebase 條款,然後按一下「繼續」
  7. (選用)Firebase 控制台中啟用 AI 輔助功能 (稱為「Gemini in Firebase」),協助您開始使用服務及簡化開發程序。
  8. (選用) 為專案設定 Google Analytics, 即可透過下列 Firebase 產品獲得最佳體驗: Firebase A/B TestingCloud MessagingCrashlyticsIn-App MessagingRemote Config (包括 個人化)。

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

  9. 按一下「新增 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,您也可以採取下列做法: