🐈

FirestoreEventで取得したデータに型をつける

2024/01/28に公開

私は普段Flutterでアプリ開発をしているのですが、最近通知機能をFirebase Functionで実装する機会がありました。

具体的には、Firestoreへのデータ保存をトリガーとして通知を送信する機能です。
そのときにデータを型安全に扱う方法に手こずったのでかんたんに紹介します。
(FirestoreEventとかFirebase Function v2の参考にもなるかも)

結論

FirestoreDataConverterfromFirestoreメソッドを使います。
https://firebase.google.com/docs/reference/js/v8/firebase.firestore.FirestoreDataConverter#fromfirestore

公式ドキュメントのExampleではFirestoreからデータを取得するときにwithConverterを使う例が紹介されています。
しかし、FirestoreEventを使う場合にはコールバック関数の引数としてデータを受け取るので、withConverterが使えません。
そこで、以下のようにconverterのfromFirestoreメソッドを直接使用します。
※コードは実際に使用しているものとは異なる最小限のものです。

chat.ts
import {
  DocumentData,
  FirestoreDataConverter,
  QueryDocumentSnapshot,
} from "firebase-admin/firestore";

class Chat {
  constructor(
    readonly chatId: string,
    readonly token: string,
    readonly content: string,
    readonly fromName: string
  ) {}
}

export const chatConverter: FirestoreDataConverter<Chat> = {
  toFirestore(chat: Chat): DocumentData {
    return {
      chatId: chat.chatId,
      tokens: chat.token,
      content: chat.content,
      fromName: chat.fromName,
    };
  },
  fromFirestore(snapshot: QueryDocumentSnapshot): Chat {
    const data = snapshot.data();
    return new Chat(
      data.chatId,
      data.token,
      data.content,
      data.fromName
    );
  },
};
index.ts
import { Message } from "firebase-admin/lib/messaging/messaging-api";
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { chatConverter } from "./models/chat";
import { sendMessage } from "./utils/send-message";

export const message = onDocumentCreated(
  "rooms/{roomId}/chats/{chatId}",
  async (event) => {
    const snap = event.data;

    if (snap === undefined) {
      console.error("No data for new message");
      return;
    }

    // ↓ココ
    const chat = chatConverter.fromFirestore(snap);

    const message: Message = {
      notification: {
        title: chat.fromName,
        body: chat.content,
      },
      token: chat.token,
    };
    sendMessage(message);
  }
);

ちゃんとChatの型がついています。わーい。

参考記事

https://qiita.com/FAL-coffee/items/3496036b7acbb3493bc1

Discussion