Cloud Functions を使用して Data Connect を拡張する

Cloud Functions for Firebase を使用すると、Firebase Data Connect 内のイベントを処理できます。Cloud Functions で、Data Connect サービスでのミューテーションの実行などのイベントに応じてサーバーサイド コードを実行できます。これにより、独自のサーバーをデプロイすることなく、カスタム ロジックを追加できます。

一般的なユースケース

  • データ同期: ミューテーションが発生した後、他のシステム(Cloud Firestore、BigQuery、外部 API など)との間でデータを複製または同期します。

  • 非同期ワークフロー: データベースの変更後に、画像処理やデータ集計などの長時間実行プロセスを開始します。

  • ユーザー エンゲージメント: アカウントの作成など、アプリケーション内の特定のミューテーション イベントが発生した後に、ユーザーにメールまたは Cloud Messaging 通知を送信します。

Data Connect ミューテーションで関数をトリガーする

onMutationExecuted イベント ハンドラを使用すると、Data Connect ミューテーションが実行されるたびに関数をトリガーできます。このトリガーは、ミューテーションの実行時に発動します。

基本的なミューテーション イベント関数

以下に挙げる基本的な例は、Data Connect サービスで実行されたミューテーションの詳細をログに記録する関数です。

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";

export const logMutation = onMutationExecuted(
  {
    /* Trigger on all mutations, spanning all services and connectors
       in us-central1 */
  },
  (event) => {
    logger.info("A mutation was executed!", {
      data: event.data,
    });
  }
);

Python

from firebase_functions import dataconnect_fn, logger

@dataconnect_fn.on_mutation_executed()
def log_mutation(event: dataconnect_fn.Event):
  logger.info("A mutation was executed!", event.data)

プロジェクト内のすべてのミューテーションをトリガーする場合は、トリガー ハンドラでミューテーションを実行しないでください。実行してしまうと無限ループが発生します。イベント トリガーでミューテーションを実行する場合は、以下で説明するフィルタリング オプションを使用し、ミューテーションが自身をトリガーしないように注意してください。

関数のロケーションを設定する

イベントで関数をトリガーするには、関数のロケーションData Connect サービスのロケーションと一致している必要があります。デフォルトでは、関数のリージョンは us-central1 です。

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";

export const onMutationRegionOption = onMutationExecuted(
  {
    region: "europe-west1"  // Set if Data Connect service location is not us-central1
  },
  (event) => { /* ... */ }
);

Python

@dataconnect_fn.on_mutation_executed(
  region="europe-west1"  # Set if Data Connect service location is not us-central1
)
def mutation_executed_handler_region_option(event: dataconnect_fn.Event):
  pass

イベントをフィルタ

onMutationExecuted ハンドラは、特定の属性に基づいてイベントをフィルタするオプションで構成できます。これは、特定のミューテーションに対してのみ関数をトリガーする場合に便利です。

serviceconnectoroperation によるフィルタが可能です。

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";

// Trigger this function only for the CreateUser mutation
// in the users connector of the myAppService service.
export const onUserCreate = onMutationExecuted(
  {
    service: "myAppService",
    connector: "users",
    operation: "CreateUser",
  },
  (event) => {
    logger.info("A new user was created!", event.data);
    // Add logic here: for example, sending a welcome email.
  }
);

Python

from firebase_functions import dataconnect_fn, logger

@dataconnect_fn.on_mutation_executed(
  service="myAppService",
  connector="users",
  operation="CreateUser"
):
def on_user_create(event: dataconnect_fn.Event):
  logger.info("A new user was created!", event.data)

ワイルドカードとキャプチャ グループ

ワイルドカードとキャプチャ グループを使用して、複数の値でトリガーをフィルタできます。キャプチャされたグループはすべて event.params で使用できます。詳細については、パスパターンについてをご覧ください。

例:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";

// Trigger on all operations that match the pattern `User*`, on any service and
// connector.
export const onMutationWildcards = onMutationExecuted(
  {
    operation: "User*",
  },
  (event) => {}
);

// Trigger on all operations that match the pattern `User*`, on any service and
// connector. Capture the operation name in the variable `op`.
export const onMutationCaptureWildcards = onMutationExecuted(
  {
    operation: "{op=User*}",
  },
  (event) => {
    // `event.params.op` contains the operation name.
  }
);

// Trigger on all operations on the service `myAppService`. Capture the
// operation name in the variable `operation`.
export const onMutationCaptures = onMutationExecuted(
  {
    service: "myAppService",
    operation: "{operation}",
  },
  (event) => {
    // `event.params.operation` contains the operation name.
  }
);

Python

from firebase_functions import dataconnect_fn

# Trigger on all operations that match the pattern `User*`, on any service and
# connector.
@dataconnect_fn.on_mutation_executed(
  operation="User*"
)
def on_mutation_wildcards(event: dataconnect_fn.Event):
  pass

# Trigger on all operations that match the pattern `User*`, on any service and
# connector. Capture the operation name in the variable `op`.
@dataconnect_fn.on_mutation_executed(
  operation="{op=User*}"
)
def on_mutation_capture_wildcards(event: dataconnect_fn.Event):
  # `event.params["op"]` contains the operation name.
  pass

# Trigger on all operations on the service `myAppService`. Capture the
# operation name in the variable `operation`.
@dataconnect_fn.on_mutation_executed(
  service="myAppService",
  operation="{operation}"
)
def on_mutation_captures(event: dataconnect_fn.Event):
  # `event.params["operation"]` contains the operation name.
  pass

ユーザー認証情報にアクセスする

イベントをトリガーしたプリンシパルに関するユーザー認証情報にアクセスできます。認証コンテキストで使用可能なデータの詳細については、認証コンテキストをご覧ください。

次の例は、認証情報を取得する方法を示しています。

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";

export const onMutation = onMutationExecuted(
  { operation: "MyMutation" },
  (event) => {
    // mutationExecuted event provides authType and authId:
    // event.authType
    // event.authId
  }
);

Python

from firebase_functions import dataconnect_fn

@dataconnect_fn.on_mutation_executed(operation="MyMutation")
def mutation_executed_handler(event: dataconnect_fn.Event):
  # mutationExecuted event provides auth_type and auth_id, which are accessed as follows
  # event.auth_type
  # event.auth_id
  pass

認証タイプと認証 ID は以下のように入力されます。

ミューテーションの開始元 authtype authid
認証済みエンドユーザー app_user Firebase Auth トークン UID
認証されていないエンドユーザー unauthenticated 指定なし
エンドユーザーの権限を借用した Admin SDK app_user 権限の借用先であるユーザーの Firebase Auth トークン UID
認証されていないリクエストを借用した Admin SDK unauthenticated 指定なし
完全な権限付き Admin SDK admin 指定なし

イベントデータにアクセスする

関数に渡される CloudEvent オブジェクトには、トリガーしたイベントに関する情報が含まれています。

イベント属性

属性 説明
id string イベントの固有識別子。
source string イベントを生成したコネクタ リソース(//firebasedataconnect.googleapis.com/projects/*/locations/*/services/*/connectors/* など)。
specversion string CloudEvents 仕様のバージョン(例: "1.0")。
type string イベント: google.firebase.dataconnect.connector.v1.mutationExecuted のタイプ。
time string イベントが生成されたときのタイムスタンプ(ISO 8601 形式)。
subject string 省略可。オペレーション名など、イベント コンテキストに関する追加情報。
params object キャプチャされたパスパターンのマップ。
authType string イベントをトリガーしたプリンシパルのタイプを表す列挙型。
authId string イベントをトリガーしたプリンシパルの固有識別子。
data MutationEventData Data Connect イベントのペイロード。次のセクションをご覧ください。

データ ペイロード

MutationEventData オブジェクトには、Data Connect イベントのペイロードが含まれます。

{
  // ...
  "authType": // ...
  "data": {
    "payload": {
      "variables": {
        "userId": "user123",
        "updateData": {
          "displayName": "New Name"
        }
      },
      "data": {
        "updateUser": {
          "id": "user123",
          "displayName": "New Name",
          "email": "user@example.com"
        }
      },
      "errors": []
    }
  }
}
  • payload.variables: ミューテーションに渡された変数を含むオブジェクト。
  • payload.data: ミューテーションによって返されたデータを含むオブジェクト。
  • payload.errors: ミューテーションの実行中に発生したエラーの配列。ミューテーションが成功した場合、この配列は空になります。

ミューテーション変数と返されたデータにアクセスする方法は次のとおりです。

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";

export const processNewUserData = onMutationExecuted(
  {
    "service": "myAppService",
    "connector": "users",
    "operation": "CreateUser",
  },
  (event) => {
    // The variables passed to the mutation
    const mutationVariables = event.data.payload.variables;

    // The data returned by the mutation
    const returnedData = event.data.payload.data;

    logger.info("Processing mutation with variables:", mutationVariables);
    logger.info("Mutation returned:", returnedData);

    // ... your custom logic here
  }
);

Python

from firebase_functions import dataconnect_fn, logger

@dataconnect_fn.on_mutation_executed(
  service="myAppService",
  connector="users",
  operation="CreateUser"
):
def process_new_user_data(event: dataconnect_fn.Event):
  # The variables passed to the mutation
  mutation_vars = event.data.payload.variables
  # The data returned by the mutation
  returned_data = event.data.payload.data

  logger.info("Processing mutation with variables:", mutationVariables)
  logger.info("Mutation returned", returnedData)

  # ... your custom logic here

Cloud FirestoreRealtime Database などの他のデータベース トリガーとは異なり、Data Connect イベントではデータの「前」のスナップショットは提供されません。Data Connect は基盤となるデータベースにリクエストをプロキシするため、データの「前」のスナップショットをトランザクション的に取得することはできません。代わりに、ミューテーションに送信された引数と、ミューテーションから返されたデータにアクセスできます。

このため、イベント トリガーが同じイベントをトリガーする無限ループを回避するために、「前」と「後」のスナップショットを比較する手法を使用することはできません。ミューテーション イベントによってトリガーされた関数からミューテーションを実行する必要がある場合は、イベント フィルタを使用し、ミューテーションが間接的であっても自身をトリガーしないように注意してください。