このページでは、シンプルな Firebase 拡張機能を作成するのに必要な手順について説明します。拡張機能は、プロジェクトにインストールしたり、他のユーザーと共有したりすることができます。このページで扱うシンプルな Firebase 拡張機能では、Realtime Database でメッセージを監視し、そのメッセージを大文字に変換します。
1. 環境を設定してプロジェクトを初期化する
拡張機能の作成を始める前に、必要なツールを使用してビルド環境を設定する必要があります。
Node.js 16 以降をインストールします。Node のインストール方法としては、nvm(または nvm-windows)を使用する方法があります。
Firebase CLI の最新バージョンをインストールするか、最新バージョンに更新します。
npm
を使用してインストールまたは更新する場合は、次のコマンドを実行します。npm install -g firebase-tools
Firebase CLI を使用して新しい拡張機能プロジェクトを初期化します。
拡張機能のディレクトリを作成し、
cd
でそのディレクトリに移動します。mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
Firebase CLI の
ext:dev:init
コマンドを実行します。firebase ext:dev:init
プロンプトが表示されたら、関数の言語として JavaScript を選択します(独自の拡張機能を開発する場合は TypeScript も使用できます)。依存関係をインストールするよう求められたら、「yes」と答えます(その他のオプションのデフォルトの値を使用します)。このコマンドにより、新しい拡張機能のスケルトン コードベースが設定され、そこから拡張機能の開発を始めることができます。
2. エミュレータを使用してサンプルの拡張機能を試す
Firebase CLI によって新しい拡張機能のディレクトリが初期化され、簡単なサンプル関数と integration-tests
ディレクトリが作成されました。このディレクトリには、Firebase Emulator Suite で拡張機能を実行するために必要なファイルが含まれています。
エミュレータを使用して、サンプルの拡張機能を実行してみましょう。
integration-tests
ディレクトリに移動します。cd functions/integration-tests
デモ プロジェクトでエミュレータを起動します。
firebase emulators:start --project=demo-test
エミュレータが、事前定義のダミー プロジェクト(
demo-test
)に拡張機能を読み込みます。この拡張機能は単一の HTTP トリガー関数greetTheWorld
で構成されています。この関数は、アクセスされると「hello world」というメッセージを返します。エミュレータを実行したまま、エミュレータの起動時に出力された URL にアクセスして、拡張機能の
greetTheWorld
関数を実行します。ブラウザに「Hello World from greet-the-world」というメッセージが表示されるはずです。
この関数のソースコードは、拡張機能の
functions
ディレクトリにあります。このソースを任意のエディタまたは IDE で開きます。functions/index.js
const functions = require("firebase-functions/v1"); exports.greetTheWorld = functions.https.onRequest((req, res) => { // Here we reference a user-provided parameter // (its value is provided by the user during installation) const consumerProvidedGreeting = process.env.GREETING; // And here we reference an auto-populated parameter // (its value is provided by Firebase after installation) const instanceId = process.env.EXT_INSTANCE_ID; const greeting = `${consumerProvidedGreeting} World from ${instanceId}`; res.send(greeting); });
エミュレータの実行中は、Functions コードに行った変更が自動的に再読み込みされます。
greetTheWorld
関数を少し変更してみましょう。functions/index.js
const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
変更を保存します。エミュレータでコードが再読み込みされます。関数の URL にアクセスしてみてください。更新された応答メッセージが表示されるはずです。
3. extension.yaml に基本的な情報を追加する
開発環境が設定され、拡張機能エミュレータが実行されています。では、独自の拡張機能の作成してみましょう。
まず、事前定義された拡張機能のメタデータを編集します。greet-the-world
ではなく、作成する拡張機能を反映します。このメタデータは extension.yaml
ファイルに格納されます。
エディタで
extension.yaml
を開き、ファイル全体を次のように置き換えます。name: rtdb-uppercase-messages version: 0.0.1 specVersion: v1beta # Firebase Extensions specification version; don't change # Friendly display name for your extension (~3-5 words) displayName: Convert messages to upper case # Brief description of the task your extension performs (~1 sentence) description: >- Converts messages in RTDB to upper case author: authorName: Your Name url: https://your-site.example.com license: Apache-2.0 # Required license # Public URL for the source code of your extension sourceUrl: https://github.com/your-name/your-repo
name
フィールドに適用される命名規則に注意してください。公式の Firebase 拡張機能の名前には、拡張機能が動作するプライマリ Firebase プロダクトを示す接頭辞が付き、その後に拡張機能の説明が続きます。独自の拡張機能でも同じ規則に従う必要があります。拡張機能の名前を変更したので、エミュレータの構成も新しい名前で更新する必要があります。
functions/integration-tests/firebase.json
で、greet-the-world
をrtdb-uppercase-messages
に変更します。functions/integration-tests/extensions/greet-the-world.env
をfunctions/integration-tests/extensions/rtdb-uppercase-messages.env
という名前に変更します。
この段階では、拡張機能コードに含まれている greet-the-world
拡張機能の残りの部分はそのままにしておきます。この部分は後で更新します。
4. Cloud Functions の関数を記述して拡張リソースとして宣言する
ここまでで、コードの作成を始める準備ができました。このステップでは、拡張機能のコアタスクを実行する Cloud Functions の関数を作成します。この関数は、Realtime Database のメッセージを監視し、大文字に変換します。
任意のエディタまたは IDE で、拡張機能の関数のソースを開きます(
functions
ディレクトリにあります)。次のように置き換えます。functions/index.js
import { database, logger } from "firebase-functions/v1"; const app = initializeApp(); // Listens for new messages added to /messages/{pushId}/original and creates an // uppercase version of the message to /messages/{pushId}/uppercase // for all databases in 'us-central1' export const makeuppercase = database .ref("/messages/{pushId}/uppercase") .onCreate(async (snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); // Convert it to upper case. logger.log("Uppercasing", context.params.pushId, original); const uppercase = original.toUpperCase(); // Setting an "uppercase" sibling in the Realtime Database. const upperRef = snapshot.ref.parent.child("upper"); await upperRef.set(uppercase); });
置き換える前の関数は、HTTP エンドポイントからアクセスされたときに実行される HTTP トリガー関数でした。新しい関数はリアルタイムのデータベース イベントによってトリガーされ、特定のパスにある新しいアイテムを監視します。検出されると、大文字の値をデータベースに書き込みます。
この新しいファイルでは、CommonJS(
require
)ではなく ECMAScript モジュール構文(import
とexport
)が使用されています。Node で ES モジュールを使用する場合は、functions/package.json
に"type": "module"
を指定します。{ "name": "rtdb-uppercase-messages", "main": "index.js", "type": "module", … }
拡張機能のすべての関数は
extension.yaml
ファイルで宣言する必要があります。このサンプルの拡張機能で宣言されていた Cloud Functions の関数はgreetTheWorld
だけで、これをmakeuppercase
に置き換えたので、その宣言も更新する必要があります。extension.yaml
を開き、resources
フィールドを追加します。resources: - name: makeuppercase type: firebaseextensions.v1beta.function properties: eventTrigger: eventType: providers/google.firebase.database/eventTypes/ref.create # DATABASE_INSTANCE (project's default instance) is an auto-populated # parameter value. You can also specify an instance. resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original runtime: "nodejs18"
変更後の拡張機能はトリガーとして Realtime Database を使用しているため、Cloud Functions エミュレータとともに RTDB エミュレータを実行するには、エミュレータの構成を更新する必要があります。
エミュレータが実行中の場合は、Ctrl+C キーを押して停止します。
functions/integration-tests
ディレクトリから次のコマンドを実行します。firebase init emulators
プロンプトが表示されたら、デフォルト プロジェクトの設定をスキップして、Functions エミュレータと Database エミュレータを選択します。デフォルトのポートを受け入れ、設定ツールが必要なファイルをダウンロードできるようにします。
エミュレータを再起動します。
firebase emulators:start --project=demo-test
更新後の拡張機能を試してみましょう。
エミュレータの起動時に出力されたリンクを使用して、Database Emulator UI を開きます。
データベースのルートノードを編集します。
- フィールド:
messages
- タイプ:
json
- 値:
{"11": {"original": "recipe"}}
すべてが正しく設定されていれば、データベースの変更を保存したときに、拡張機能の
makeuppercase
関数によって子レコードがトリガーされ、メッセージ 11 にコンテンツ"upper": "RECIPE"
が追加されます。エミュレータ UI のログとデータベース タブを調べて、期待される結果になっているかどうか確認します。- フィールド:
messages
ノード({"original":"any text"}
)にさらに子を追加してみましょう。新しいレコードを追加するたびに拡張機能がuppercase
フィールドを追加し、そのフィールドにoriginal
フィールドの内容を大文字にした結果が保存されているはずです。
これで、RTDB インスタンス上で動作するシンプルな拡張機能が完成しました。以降のセクションでは、この拡張機能に機能を追加して改良していきます。さらに、拡張機能を他のユーザーに配布できるようにし、最後に Extensions Hub で公開します。
5. API とロールを宣言する
Firebase は、インストールされた拡張機能の各インスタンスに対して、インスタンスごとのサービス アカウントを使用してプロジェクトとそのデータへのアクセスを制限付きで許可します。各アカウントには、オペレーションに必要な最小限の権限セットが含まれています。このため、拡張機能に必要な IAM ロールを明示的に宣言する必要があります。ユーザーが拡張機能をインストールすると、Firebase はこれらのロールが付与されているサービス アカウントを作成し、そのアカウントを使用して拡張機能を実行します。
プロダクトのイベントでトリガーするためにロールを宣言する必要はありませんが、他の方法で操作する場合はロールを宣言する必要があります。前の手順で追加した関数は Realtime Database に書き込みを行うため、次の宣言を extension.yaml
に追加する必要があります。
roles:
- role: firebasedatabase.admin
reason: Allows the extension to write to RTDB.
同様に、拡張機能が使用する Google API を apis
フィールドで宣言します。ユーザーが拡張機能をインストールすると、プロジェクトでこれらの API を自動的に有効にするかどうかを尋ねるメッセージが表示されます。これは Firebase 以外の Google API で必要になる操作で、このガイドでは行う必要はありません。
6. ユーザー構成可能なパラメータを定義する
前の 2 つの手順で作成した関数は、特定の RTDB の場所で受信メッセージを監視する関数です。拡張機能専用のデータベース構造で拡張機能が動作している場合などは、所定の場所での監視が必要になりますが、ほとんどの場合は、プロジェクトに拡張機能をインストールするユーザーがこれらの値を構成できるようにする必要があります。これにより、ユーザーが既存のデータベース設定で拡張機能を使用できるようになります。
拡張機能が新しいメッセージを監視するパスをユーザーが構成できるようにします。
extension.yaml
ファイルにparams
セクションを追加します。- param: MESSAGE_PATH label: Message path description: >- What is the path at which the original text of a message can be found? type: string default: /messages/{pushId}/original required: true immutable: false
これにより、拡張機能のインストール時にユーザーに設定を求める新しい文字列パラメータが定義されます。
extension.yaml
ファイルのmakeuppercase
宣言に戻り、resource
フィールドを次のように変更します。resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
${param:MESSAGE_PATH}
トークンは、先ほど定義したパラメータの参照です。拡張機能の実行時に、このトークンはユーザーが構成したパラメータの値に置き換えられ、makeuppercase
関数はユーザーが指定したパスをリッスンします。この構文を使用すると、extension.yaml
内にあるどのユーザー定義パラメータでも参照することができます(POSTINSTALL.md
内のユーザー定義パラメータも参照できます。こちらについて後で詳しく説明します)。また、関数コードからユーザー定義パラメータにアクセスすることもできます。
前のセクションで作成した関数では、変更を監視するパスがハードコードされています。ユーザー定義の値を参照するようにトリガーの定義を変更します。
functions/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
この変更は説明を目的としたものです。Firebase Extensions では、Cloud Functions の関数を拡張機能の一部としてデプロイすると、
extension.yaml
ファイルのトリガー定義が使用されます。関数定義で指定された値は無視されます。それでも、この値の出所をコードに記述しておくことをおすすめします。ランタイムに影響のないコード変更は無駄に感じるかもしれませんが、関数コード内のユーザー定義パラメータにアクセスして、関数のロジックで通常の値として使用できることを覚えておいてください。この点は重要です。次のログ ステートメントを追加して、ユーザーが定義した値に実際にアクセスできることを確認してみましょう。
functions/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate( async (snapshot, context) => { logger.log("Found new message at ", snapshot.ref); // Grab the current value of what was written to the Realtime Database. ...
通常、拡張機能のインストール時に、ユーザーはパラメータの値を指定するように求められます。テストと開発でエミュレータを使用している場合は、インストール プロセスをスキップし、代わりに
env
ファイルにユーザー定義パラメータの値を指定します。functions/integration-tests/extensions/rtdb-uppercase-messages.env
を開き、GREETING
定義を次のように置き換えます。MESSAGE_PATH=/msgs/{pushId}/original
上記のパスはデフォルトのパスや以前に定義したパスとは異なります。これは、更新後の拡張機能で定義が機能していることを確認するためのものです。
エミュレータを再起動して、データベースのエミュレータ UI にアクセスします。
上で定義したパスを使用して、データベースのルートノードを編集します。
- フィールド:
msgs
- タイプ:
json
- 値:
{"11": {"original": "recipe"}}
データベースの変更を保存すると、前と同じように拡張機能の
makeuppercase
関数がトリガーされますが、ユーザー定義パラメータもコンソールログに出力されているはずです。- フィールド:
7. ユーザー定義ロジックのイベントフックを提供する
拡張機能を作成しながら、Firebase プロダクトが拡張機能提供のロジックをトリガーする仕組みも確認しました。この例では、Realtime Database で新しいレコードを作成すると、makeuppercase
関数がトリガーされます。この仕組みは拡張機能とそれをインストールしたユーザーの関係と似ています。拡張機能はユーザーが定義したロジックをトリガーできます。
拡張機能では、同期フック、非同期フック、またはその両方を使用できます。同期フックを使用すると、拡張機能の 1 つの関数の完了をブロックするタスクを実行できます。これは、拡張機能が機能する前にユーザーがカスタム前処理を実行できるようにする場合に役立ちます。
このガイドでは、拡張機能に非同期フックを追加し、大文字のメッセージが Realtime Database に書き込まれた後に実行される独自の処理ステップをユーザーが定義できるようにします。非同期フックは、Eventarc を使用してユーザー定義関数をトリガーします。拡張機能は出力するイベントのタイプを宣言し、ユーザーは拡張機能のインストール時に目的のイベントタイプを選択します。イベントを少なくとも 1 つ選択すると、Firebase はインストール プロセスの一環として、拡張機能の Eventarc チャネルをプロビジョニングします。ユーザーは、そのチャネルをリッスンし、拡張機能が新しいイベントを公開したときにトリガーされる独自の Cloud Functions の関数をデプロイできます。
非同期フックを追加する手順は次のとおりです。
extension.yaml
ファイルに次のセクションを追加します。このセクションでは、拡張機能が出力するイベントのタイプを 1 つ宣言します。events: - type: test-publisher.rtdb-uppercase-messages.v1.complete description: >- Occurs when message uppercasing completes. The event subject will contain the RTDB URL of the uppercase message.
イベントのタイプはユニバーサルに一意である必要があります。一意性を確保するため、イベントの名前は常に
<publisher-id>.<extension-id>.<version>.<description>
という形式にします(パブリッシャー ID はまだないため、ここではtest-publisher
を使用してください)。makeuppercase
関数の最後に、宣言したタイプのイベントを公開するコードを追加します。functions/index.js
// Import the Eventarc library: import { initializeApp } from "firebase-admin/app"; import { getEventarc } from "firebase-admin/eventarc"; const app = initializeApp(); // In makeuppercase, after upperRef.set(uppercase), add: // Set eventChannel to a newly-initialized channel, or `undefined` if events // aren't enabled. const eventChannel = process.env.EVENTARC_CHANNEL && getEventarc().channel(process.env.EVENTARC_CHANNEL, { allowedEventTypes: process.env.EXT_SELECTED_EVENTS, }); // If events are enabled, publish a `complete` event to the configured // channel. eventChannel && eventChannel.publish({ type: "test-publisher.rtdb-uppercase-messages.v1.complete", subject: upperRef.toString(), data: { "original": original, "uppercase": uppercase, }, });
このサンプルコードでは、ユーザーが少なくとも 1 つのイベントタイプを有効にしたときにのみ
EVENTARC_CHANNEL
環境変数が定義される点を利用しています。EVENTARC_CHANNEL
が定義されていない場合、イベントは公開されません。Eventarc イベントには追加情報を追加できます。上の例では、イベントの
subject
フィールドに新しく作成した値への参照とdata
ペイロードが含まれています。このペイロードには、元のメッセージと大文字に変換したメッセージが含まれています。イベントをトリガーするユーザー定義関数でこの情報を利用できます。通常、
EVENTARC_CHANNEL
環境変数とEXT_SELECTED_EVENTS
環境変数は、ユーザーがインストール時に選択したオプションに基づいて定義されます。エミュレータを使用してテストする場合は、rtdb-uppercase-messages.env
ファイルで次の変数を定義します。EVENTARC_CHANNEL=locations/us-central1/channels/firebase EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
これで、拡張機能に非同期イベントフックが追加されました。
実装した新しい機能を試してみましょう。次のステップでは、拡張機能をインストールするユーザーのロールを前提としています。
functions/integration-tests
ディレクトリから、新しい Firebase プロジェクトを初期化します。firebase init functions
プロンプトが表示されたら、デフォルト プロジェクトの設定を拒否します。Cloud Functions の言語として JavaScript を選択し、必要な依存関係をインストールします。このプロジェクトは、拡張機能をインストールしたユーザーのプロジェクトです。
integration-tests/functions/index.js
を編集して、次のコードを貼り付けます。import { logger } from "firebase-functions/v1"; import { onCustomEventPublished } from "firebase-functions/v2/eventarc"; import { initializeApp } from "firebase-admin/app"; import { getDatabase } from "firebase-admin/database"; const app = initializeApp(); export const extraemphasis = onCustomEventPublished( "test-publisher.rtdb-uppercase-messages.v1.complete", async (event) => { logger.info("Received makeuppercase completed event", event); const refUrl = event.subject; const ref = getDatabase().refFromURL(refUrl); const upper = (await ref.get()).val(); return ref.set(`${upper}!!!`); } );
これは、ユーザーが作成する後処理関数の例です。この例では、拡張機能による
complete
イベントの公開をリッスンし、トリガーされると、大文字に変換されたメッセージに感嘆符を 3 つ追加します。エミュレータを再起動します。エミュレータは、拡張機能の関数とユーザー定義の後処理関数を読み込みます。
データベース エミュレータ UI にアクセスして、上で定義したパスを使用してデータベースのルートノードを編集します。
- フィールド:
msgs
- タイプ:
json
- 値:
{"11": {"original": "recipe"}}
データベースの変更を保存すると、拡張機能の
makeuppercase
関数とユーザー定義のextraemphasis
関数が順番にトリガーされ、upper
フィールドの値がRECIPE!!!
になるはずです。- フィールド:
8. ライフサイクル イベント ハンドラを追加する
ここで作成しているのは、メッセージが作成されたときにそのメッセージを処理する拡張機能です。では、ユーザーが拡張機能をインストールするときにすでに、データベースにメッセージが存在する場合はどうなるでしょうか。Firebase Extensions にはライフサイクル イベント フックという機能があります。この機能を利用すると、拡張機能のインストール、更新、再構成時にアクションをトリガーできます。このセクションでは、ライフサイクル イベントフックを使用して、拡張機能のインストール時にプロジェクトにすでに存在しているメッセージを大文字に変換し、変換後のメッセージをデータベースにバックフィルします。
Firebase Extensions は、Cloud Tasks を使用してライフサイクル イベント ハンドラを実行します。イベント ハンドラは Cloud Functions を使用して定義します。ハンドラを定義すると、拡張機能のインスタンスがサポートされているライフサイクル イベントのいずれかに到達すると、ハンドラが Cloud Tasks キューに追加されます。Cloud Tasks はハンドラを非同期的に実行します。ライフサイクル イベント ハンドラの実行中に、処理中のタスクの存在が Firebase コンソールから拡張機能インスタンスに報告されます。タスクの進行状況と完了をユーザーに報告するかどうかは、ハンドラ関数で判断します。
既存のメッセージをバックフィルするライフサイクル イベント ハンドラを追加するには、次の操作を行います。
タスクキュー イベントによってトリガーされる新しい Cloud Functions の関数を定義します。
functions/index.js
import { tasks } from "firebase-functions/v1"; import { getDatabase } from "firebase-admin/database"; import { getExtensions } from "firebase-admin/extensions"; import { getFunctions } from "firebase-admin/functions"; export const backfilldata = tasks.taskQueue().onDispatch(async () => { const batch = await getDatabase() .ref(process.env.MESSAGE_PATH) .parent.parent.orderByChild("upper") .limitToFirst(20) .get(); const promises = []; for (const key in batch.val()) { const msg = batch.child(key); if (msg.hasChild("original") && !msg.hasChild("upper")) { const upper = msg.child("original").val().toUpperCase(); promises.push(msg.child("upper").ref.set(upper)); } } await Promise.all(promises); if (promises.length > 0) { const queue = getFunctions().taskQueue( "backfilldata", process.env.EXT_INSTANCE_ID ); return queue.enqueue({}); } else { return getExtensions() .runtime() .setProcessingState("PROCESSING_COMPLETE", "Backfill complete."); } });
この関数は、タスクキューに自身を追加する前にいくつかのレコードを処理します。これは、Cloud Functions のタイムアウト期間内に完了できないタスクに対応する際によく使用される手法です。ユーザーが拡張機能をインストールするときに、どのくらいの数のメッセージがデータベース内に存在するかは予測が難しいため、このような場合には適した方法です。
extension.yaml
ファイルで、taskQueueTrigger
プロパティを持つ拡張リソースとしてバックフィル関数を宣言します。resources: - name: makeuppercase ... - name: backfilldata type: firebaseextensions.v1beta.function description: >- Backfill existing messages with uppercase versions properties: runtime: "nodejs18" taskQueueTrigger: {}
次に、この関数を
onInstall
ライフサイクル イベントのハンドラとして宣言します。lifecycleEvents: onInstall: function: backfilldata processingMessage: Uppercasing existing messages
既存のメッセージのバックフィルは重要ですが、それがなくても拡張機能が機能することもあります。このような場合は、ライフサイクル イベント ハンドラの実行をオプションにする必要があります。
その場合は
extension.yaml
に新しいパラメータを追加します。- param: DO_BACKFILL label: Backfill existing messages description: >- Generate uppercase versions of existing messages? type: select required: true options: - label: Yes value: true - label: No value: false
次に、バックフィル関数の先頭で、
DO_BACKFILL
パラメータの値を確認し、値が設定されていない場合は早めに終了します。functions/index.js
if (!process.env.DO_BACKFILL) { return getExtensions() .runtime() .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped."); }
上記の変更により、拡張機能のインストール時に既存のメッセージが大文字に変換されるようになりました。
ここまでは拡張機能エミュレータを使用して拡張機能を作成し、変更をテストしてきました。ただし、拡張機能エミュレータはインストール プロセスをスキップするため、onInstall
イベント ハンドラをテストするには、実際のプロジェクトに拡張機能をインストールする必要があります。自動バックフィル機能を追加したので、このチュートリアルの拡張機能のコードはこれで完成です。
9. 実際の Firebase プロジェクトにデプロイする
拡張機能エミュレータは、拡張機能の迅速なイテレーション開発に優れたツールですが、ある時点で、実際のプロジェクトで試してみることも必要です。
そのために、まず新しいプロジェクトを設定して、いくつかのサービスを有効にします。
- Firebase コンソールで、新しいプロジェクトを追加します。
- プロジェクトを従量課金制の Blaze プランにアップグレードします。Cloud Functions for Firebase ではプロジェクトに請求先アカウントが必要であるため、拡張機能をインストールするには請求先アカウントが必要になります。
- 新しいプロジェクトで、Realtime Database を有効にします。
- 拡張機能のインストール時に既存のデータをバックフィルする機能をテストするため、Realtime Database インスタンスにサンプルデータをインポートします。
- シード RTDB データをいくつかダウンロードします。
- Firebase コンソールの [Realtime Database] ページで (展開)> [JSON をインポート] をクリックして、ダウンロードしたファイルを選択します。
バックフィル関数を有効にして
orderByChild
メソッドを使用するには、upper
の値でメッセージのインデックスを作成するようにデータベースを構成します。{ "rules": { ".read": false, ".write": false, "messages": { ".indexOn": "upper" } } }
次に、ローカルソースから新しいプロジェクトに拡張機能をインストールします。
Firebase プロジェクト用の新しいディレクトリを作成します。
mkdir ~/extensions-live-test && cd ~/extensions-live-test
作業ディレクトリで Firebase プロジェクトを初期化します。
firebase init database
プロンプトが表示されたら、作成したプロジェクトを選択します。
ローカルの Firebase プロジェクトに拡張機能をインストールします。
firebase ext:install /path/to/rtdb-uppercase-messages
ここでは、Firebase CLI ツールを使用して拡張機能をインストールした場合のユーザー エクスペリエンスを確認できます。構成ツールが既存のデータベースをバックフィルするかどうかを尋ねられたら、必ず「yes」を選択してください。
構成オプションを選択すると、Firebase CLI により構成が
extensions
ディレクトリに保存されます。また、拡張機能のソースの場所がfirebase.json
ファイルに記録されます。この 2 つのレコードを総称して拡張機能のマニフェストといいます。ユーザーは、マニフェストを使用して拡張機能の構成を保存し、別のプロジェクトにデプロイできます。拡張機能の構成を実際のプロジェクトにデプロイします。
firebase deploy --only extensions
問題がなければ、Firebase CLI によって拡張機能がプロジェクトにアップロードされ、インストールされます。インストールが完了すると、バックフィル タスクが実行され、数分以内に大文字のメッセージでデータベースが更新されます。いくつかの新しいノードをメッセージ データベースに追加して、拡張機能が新しいメッセージでも機能していることを確認します。
10. ドキュメントを作成する
拡張機能をユーザーと共有する前に、ユーザーが正常に使用できるように、十分なドキュメントを用意してください。
拡張機能のプロジェクトを初期化したときに、Firebase CLI により必要最小限のドキュメントのスタブ バージョンが作成されました。作成した拡張機能が正確に反映されているように、これらのファイルを更新します。
extension.yaml
このファイルは拡張機能の開発中に更新しているので、これ以上更新する必要はありません。
ただし、このファイルに含まれるドキュメントの重要性は忘れないでください。extension.yaml
ファイルには、拡張機能の重要な識別情報(名前、説明、作成者、公式リポジトリの場所)に加えて、リソースやユーザーが構成できるパラメータに関するユーザー向けのドキュメントが含まれています。この情報は、Firebase コンソール、Extensions Hub、Firebase CLI でユーザーに表示されます。
PREINSTALL.md
このファイルでは、ユーザーが拡張機能をインストールする前に必要な情報を提供します。拡張機能の内容、前提条件、拡張機能のインストールによって発生する料金などについて簡単な説明を記述してください。ウェブサイトに追加情報がある場合は、ここにリンクを含めます。
このファイルのテキストは、Extensions Hub と firebase ext:info
コマンドでユーザーに表示されます。
PREINSTALL ファイルの例を示します。
Use this extension to automatically convert strings to upper case when added to
a specified Realtime Database path.
This extension expects a database layout like the following example:
"messages": {
MESSAGE_ID: {
"original": MESSAGE_TEXT
},
MESSAGE_ID: {
"original": MESSAGE_TEXT
},
}
When you create new string records, this extension creates a new sibling record
with upper-cased text:
MESSAGE_ID: {
"original": MESSAGE_TEXT,
"upper": UPPERCASE_MESSAGE_TEXT,
}
#### Additional setup
Before installing this extension, make sure that you've
[set up Realtime Database](https://firebase.google.com/docs/database/quickstart)
in your Firebase project.
#### Billing
To install an extension, your project must be on the
[Blaze (pay as you go) plan](https://firebase.google.com/pricing).
- This extension uses other Firebase and Google Cloud Platform services, which
have associated charges if you exceed the service's no-cost tier:
- Realtime Database
- Cloud Functions (Node.js 10+ runtime)
[See FAQs](https://firebase.google.com/support/faq#extensions-pricing)
- If you enable events,
[Eventarc fees apply](https://cloud.google.com/eventarc/pricing).
POSTINSTALL.md
このファイルには、ユーザーが拡張機能を正常にインストールした後に役立つ情報(フォローアップの設定手順、拡張機能の動作例など)が含まれています。
POSTINSTALL.md の内容は、拡張機能を構成してインストールした後、Firebase コンソールに表示されます。このファイルのユーザー パラメータは参考情報です。これらは構成した値に置き換えられます。
チュートリアルの拡張機能をインストールした後のファイルの例を示します。
### See it in action
You can test out this extension right away!
1. Go to your
[Realtime Database dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/database/${param:PROJECT_ID}/data) in the Firebase console.
1. Add a message string to a path that matches the pattern `${param:MESSAGE_PATH}`.
1. In a few seconds, you'll see a sibling node named `upper` that contains the
message in upper case.
### Using the extension
We recommend adding data by pushing -- for example,
`firebase.database().ref().push()` -- because pushing assigns an automatically
generated ID to the node in the database. During retrieval, these nodes are
guaranteed to be ordered by the time they were added. Learn more about reading
and writing data for your platform (iOS, Android, or Web) in the
[Realtime Database documentation](https://firebase.google.com/docs/database/).
### Monitoring
As a best practice, you can
[monitor the activity](https://firebase.google.com/docs/extensions/manage-installed-extensions#monitor)
of your installed extension, including checks on its health, usage, and logs.
CHANGELOG.md
拡張機能のリリース間で行った変更は CHANGELOG.md
ファイルに文書化する必要があります。
このサンプルの拡張機能はまだ公開されていないため、変更ログのエントリは 1 つだけです。
## Version 0.0.1
Initial release of the _Convert messages to upper case_ extension.
README.md
ほとんどの拡張機能は、ユーザーが拡張機能のリポジトリにアクセスしたときに役立つように、readme ファイルを提供しています。このファイルは手動で作成することも、コマンドで生成することもできます。
このガイドでは、readme ファイルの作成については説明しません。
その他のドキュメント
前述のドキュメントは、ユーザーに提供する必要のあるドキュメントの最小セットです。多くの場合、ユーザーが拡張機能を正常に使用できるように、より詳細なドキュメントを用意する必要があります。そのような場合は、追加のドキュメントを作成して、ユーザーが参照できる場所にホストしてください。
このガイドでは、詳細なドキュメントの作成について説明しません。
11. Extensions Hub で公開する
拡張機能のコードが完成してドキュメントを用意したので、拡張機能を Extensions Hub で公開する準備ができました。ただし、これはチュートリアルですので、公開は行わないでください。このチュートリアルと Firebase Extensions パブリッシャー向けドキュメントの残りの部分で学んだことを基に、Firebase で作成された公式の拡張機能のソースを調べて、独自の拡張機能を作成してください。
Extensions Hub で公開する準備ができたら、以下の操作を行います。
- 拡張機能を初めて公開する場合は、拡張機能のパブリッシャーとして登録します。拡張機能のパブリッシャーとして登録する際には、拡張機能の作成者であることをユーザーが簡単に特定できるパブリッシャー ID を作成します。
公開されている検証可能な場所に、拡張機能のソースコードをホストします。検証可能なソースからコードを提供すると、Firebase は拡張機能をその場所から直接公開できます。これにより、現在リリースされている拡張機能のバージョンが確実に公開されるようになります。また、ユーザーがプロジェクトにインストールするコードを確認できるようになります。
現時点では、拡張機能を公開 GitHub リポジトリで提供できます。
firebase ext:dev:upload
コマンドを使用して、Extensions Hub に拡張機能をアップロードします。Firebase コンソールのパブリッシャー ダッシュボードに移動し、アップロードした拡張機能を見つけて、[Extensions Hub で公開] をクリックします。審査担当者による審査を申請します。審査には数日かかることがあります。承認されると、拡張機能が Extensions Hub に公開されます。拒否された場合は、その理由を説明するメッセージが届きます。報告された問題を解決して再度審査を依頼できます。