TL;DR
- FirebaseのRealtime DatabaseのイベントをCloud Functions for Firebaseでキャッチする
- Realtime Databaseの特定のパスのデータの変更内容を検知する
About
Firebase Realtime Database(以下DB)内で発火されたイベントを取得し、変更内容を確認したいことが動機です。
Cloud Functions for Firebase(以下Function)公式ドキュメントで提示されているトリガーで、実際にGCPのログエクスプローラでの確認まで行います。
Realtime Database トリガー | Cloud Functions for Firebase
version
- firebase (cli)
- 13.7.3
- node
- 20
Code
How to
プロジェクトのauth
FirebaseはBlazeプランを選択し、認証を行います。
gcloud auth login gcloud auth application-default login firebase login <email>
Firebaseのローカル環境を作成
Firebaseのデプロイ環境を作成します。
$ firebase init
以下の機能の使用を選択 - Realtime Database - Functions - Emulators - 任意
? Please select an option
に対して、既存のプロジェクトの使用を選択。
> Use an existing project
Realtime Databaseを作成していない場合、以下の問いが表示されるのでY(es)。
? It seems like you haven’t initialized Realtime Database in your project yet. Do you want to set it up? (Y/n)
その後どのリージョンにDBのインスタンスを配置するか聞かれるので、今回は日本に近いシンガポールリージョンを選択。
? Please choose the location for your default Realtime Database instance: us-central1 europe-west1 > asia-southeast1
その後はDBのルール・言語・エミュレータの使用などを問われるので、TypeScriptを選択する以外は適宜。
DBへダミーデータを挿入
users/
パス配下に適当なユーザーオブジェクトを作成。
e.g.: users/
配下に one
, two
というオブジェクトを追加するコード。
https://github.com/y-ohgi/blog-firebase-db-event/blob/main/scripts/scr/write.ts
const userRef = db.ref('users'); (async () => { await userRef.set({ one: { name: faker.internet.userName(), bio: faker.lorem.lines() }, two: { name: faker.internet.userName(), bio: faker.lorem.lines() } }) .then(() => { console.log('done') }) .catch(console.error) process.exit(0) })();
以下のようにダミーデータを挿入できていれば成功。
リスナーFunctionを作成
DBの /users/{uid}
配下の変更を検知するFunctionを作成します。
$ firebase init
で作成された functions/src/index.ts
がFunctionのコードになります。
onValueWritten
を使用して全てのイベントに対して発火するようにします。
https://github.com/y-ohgi/blog-firebase-db-event/blob/main/functions/src/index.ts
import * as admin from "firebase-admin"; import * as logger from "firebase-functions/logger"; import {setGlobalOptions} from "firebase-functions/v2"; import {onValueWritten} from "firebase-functions/v2/database"; admin.initializeApp(); // MEMO: // Realtime Databaseと同じリージョンで実行したいため、asia-southeast1を指定。 // また、CPU/Memoryなどの設定もここで指定可能。 setGlobalOptions({ region: "asia-southeast1", }); // "/users/{uid}" 配下で発生したイベントをリッスン const onUserWritten = onValueWritten("users/{uid}", (event) => { logger.log(event); }); export = {onUserWritten}
以下のコマンドでFunctionをデプロイ。
$ firebase deploy --only functions -P <YOUR PROJECT>
NIT:
GCPのEventarcサービスを使用するため、Eventarcサービスエージェントが作成されていない場合失敗する可能性があります(1敗)。
サービスエージェントの更新を待ち(5分ほど)、再度デプロイすると成功する可能性があります。
ログの確認
デプロイが完了するとFunctionsのダッシュボードに関数が追加されています。
ログを表示 、からログエクスプローラへ移り、Realtime Databaseを更新しイベントが発火されていることを確認します。
所感
指定したパス配下(e.g. /users/{uid}
)の更新を無邪気にトリガーしてくれるので、容量用法を守って使用したい次第です。
また、Eventarcの対応幅に圧倒されました。なんでもできますねEventarc。apigeeeまで対応しているのは流石にびっくりです。