🕸️

【TS】NestJSでFirebaseを使ってプッシュ通知を送るモック作成

2021/09/16に公開

概要

今回はNestJSからfirebase-adminを使って端末にプッシュ通知を送るモックを作成する手順の私的メモです。
同様の構成でプッシュ通知の導通を試したい方もいるかなと思い記事にしました。

前提条件としてFirebaseのプロジェクトは作成済みで、アプリ側にもFirebaseは組み込み済み(=プッシュ通知を受け取る準備ができている)ものとします。

NestJSとは

以下公式サイトです。
https://nestjs.com/

以下のような説明があります。

A progressive Node.js framework for building efficient, reliable and scalable server-side applications.

要するに「効率よく、スケールしやすいNode.jsのサーバーサイドフレームワーク」です。
Expressあたりがライバルになるかと思いますが、デフォでTypescriptに対応している等々、今風な開発ならこちらを使うと馴染みがいいかもしれません。

プロジェクト作成と初回起動

以下コマンドでプロジェクトを作成します。

npx @nestjs/cli new fcm-mock

コマンドライン上でいくつかの質問に答えた後、プロジェクトが作成されます。
早速動かしてみましょう。

cd fcm-mock
yarn start:dev

デフォルトではlocalhost:3000でサービスが立ち上がります。
ブラウザ等からアクセスするとHello Worldの文字が返ります。

ライブラリの追加

今回モックを作るにあたって使うライブラリはfirebase-admin@nestjs/configです。
前者はFirebaseを用いたプッシュ通知のため、後者はFirebaseのプロジェクトに関する認証情報などを環境変数に持たせるためのものです。

yarn add @nestjs/config
yarn add firebase-admin

サービスアカウントのJSONファイルのダウンロード

Firebaseの管理画面から【サービスアカウント】のページにアクセスし、【新しい秘密鍵の生成】を押下します。

download_json

しばらく待っているとJSONファイルがダウンロードできるので、その中にあるproject_idprivate_keyclient_emailの文字列を控えておきましょう。

認証情報の設定

本来はサーバー側の環境変数に先ほどダウンロードした認証情報を持たせますが、ここでは簡単のためにソースコード中で持つようにします。

.envファイルの作成

プロジェクトのルートに.envファイルを作成し、以下のように記載しましょう。

.env
FIREBASE_PROJECT_ID=【ダウンロードしたJSONのproject_id】
FIREBASE_PRIVATE_KEY=【ダウンロードしたJSONのprivate_key】
FIREBASE_CLIENT_EMAIL=【ダウンロードしたJSONのclient_email】

app.module.tsの更新

上記で設定した内容をモジュールが使用できるようにsrc/app.module.tsを更新します。

src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config' // 追加

@Module({
  // importsの中でConfigModuleを使うよう指定する
  imports: [ConfigModule.forRoot({
    // 参照する環境変数として.envを指定する
    envFilePath: '.env'
  })],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }

main.tsの更新

ここまででFirebaseの認証情報を読み込めるようになったので、サービス起動時にfirebase-adminを初期化するようにsrc/main.tsを更新します。

src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as admin from 'firebase-admin'; // 追加
import { ServiceAccount } from "firebase-admin"; // 追加
import { ConfigService } from '@nestjs/config'; // 追加

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Configの読み込み
  const configService: ConfigService = app.get(ConfigService);
  // Configから読み込んだ値を指定してfirebase-admin用のConfigオブジェクトを作成
  const adminConfig: ServiceAccount = {
    projectId: configService.get<string>('FIREBASE_PROJECT_ID'),
    privateKey: configService.get<string>('FIREBASE_PRIVATE_KEY').replace(/\\n/g, '\n'),
    clientEmail: configService.get<string>('FIREBASE_CLIENT_EMAIL'),
  };
  // firebase-adminの初期化
  admin.initializeApp({
    credential: admin.credential.cert(adminConfig)
  });

  await app.listen(3000);
}
bootstrap();

app.service.tsの更新

実際にデバイスに対してプッシュ通知を送信する処理を記載します。
場所はsrc/app.service.tsです。
以下のコードではモックなので、デバイスのトークンを固定としています。

src/app.service.ts
import { Injectable } from '@nestjs/common';
import * as admin from 'firebase-admin'; // 追加

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }

  // sendFcmというプッシュ通知を送信する処理を追加する
  async sendFcm() {
    const TOKEN = '【端末のトークン】';
    return await admin.messaging().sendToDevice(TOKEN, {
      notification: {
        title: "Test title",
        body: "This Message is Test."
      }
    });
  }
}

app.controller.tsの更新

先ほど作成したsendFcmを実行するエンドポイントを記載します。
戻り値としてはFirebaseに送信した結果をそのまま返すものとします。

src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import * as admin from 'firebase-admin'; // 追加

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) { }

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }

  // fcmというエンドポイントを追加する
  @Get('fcm')
  async fcm(): Promise<admin.messaging.MessagingDevicesResponse> {
    // 先ほど作成したプッシュ通知送信処理
    return await this.appService.sendFcm();
  }
}

実行

これで実行の準備が整いました。
再びyarn start:devでサービスを起動しlocalhost:3000/fcmのエンドポイントを叩いてみましょう。

以下のように端末にプッシュ通知が届けば成功です。

レスポンス

ちなみにレスポンスは以下のようになります。

{
  "results": [
      {
        "messageId":"XXXXXXXXXXXXXXXXXXXx"
      }
    ],
  "canonicalRegistrationTokenCount":0,
  "failureCount":0,
  "successCount":1,
  "multicastId":999999999999999
}

まとめ

今回はNestJSからfirebase-adminを使ってプッシュ通知を送信するモックを作成しました。
実際にはここにDB接続や認証チェックなどの肉付けをすう必要があります。

とはいえ構築からプッシュ通知の導通まで簡単に確認できたので、モックアプリを用いた簡単なデモ程度なら十分だと思います。
個人的な意見ですがTypescriptをデフォで使えてサクサクと書けるのでNestJS自体もなかなかオススメです。

今回の内容が役立てば幸いです。

参考

https://firebase.google.com/docs/cloud-messaging/send-message?hl=ja#send-messages-to-specific-devices

https://dev.to/aswinsanakan/how-to-integrate-firebase-in-nestjs-5gl9

Discussion