Nest.jsとFireStoreを連携させる

2025/03/20に公開

こんにちは、naoです。
今回普段使い慣れているNest.jsと個人開発の味方のFireStoreを
連携した手順を構築したいと思います。

Firebaseブロジェクト初期設定

firebase
ご自身のアカウントでログインをし、「プロジェクトを作成」をクリックします。
プロジェクト名を任意のもので設定をし、「続行」をクリックします。

次にFirebaseプロジェクトのAIアシスタンス設定の画面に遷移しますが
こちらはお好みで有効にします(この機能が追加されているのを知らなかった)

次にg4の有効化について聞かれますが、バックエンドとしてFireStoreを使うだけなので
ここはOFFにします。

その後、プロジェクトが作成されるので「続行」をクリックしましょう。
作成したプロジェクトに遷移すると思います。

FireStore設定

プロジェクトのサイドバーから「Firestore Database」をクリック->「データベースを作成」
ロケーションを今回は「asia-northeast1 (Tokyo)」に選択

次にルールについて問われますが、一旦「テストモード」で開始します。

Firebaseプロジェクト webアプリ設定

次にwebアプリの設定をします。
firebaseを使うのにはkey等が必要なのでこれから取得するための設定をします。

サイドバー上の設定アイコンをクリックし、「全般」タブを下までスクロールし
マイアプリのWebアイコンをクリック

アプリのニックネームは任意のもの。「Hosting」は使用しないのでチェックを外しましょう。

次にFirebase SDKの追加は「npmを使用する」をチェックし「コンソールに進む」をクリック

次にサイドバー上の設定アイコンをクリックし、「サービスアカウント」タブを下までスクロールし
今回はNode.jsを使用するので、チェックをし、「新しい秘密鍵を生成」をクリック。
こちらは後ほど、Nest.jsに設定で使用するので、ご自身がわかる場所に保存してください。

Nest.jsアプリケーションの作成

ここからはNest.jsのアプリを作成します。
まだ@nestjs/cliはグローバルにインストールした上でアプリを作成しましょう。
パッケージマネージャの選択を求められるので、任意のもので。
作成後はサーバを立ち上げます。
http://localhost:3000/ にて「Hello World!」が出ればOKです👍

npm i -g @nestjs/cli
nest new project-name
npm run dev:start

Nest.js firebase-admin設定

次に先ほど作成したfirebaseプロジェクトを組み込んでいきます。
npmライブラリではfirebasefirebase-adminがあるのですが、違いは以下

項目 Firebase SDK Firebase Admin SDK
使用環境 クライアントサイド (Web, iOS, Android) サーバーサイド (Node.js, Java, Python など)
権限レベル ユーザーごとのアクセス制御(セキュリティルール適用) 管理者権限(セキュリティルールを無視可能)
主な用途 エンドユーザーの認証、データの読み書き、リアルタイム通信 ユーザー管理、データベース管理、プッシュ通知送信
認証関連 ユーザー自身の認証・ログイン処理をサポート ユーザーの作成・更新・削除、カスタム認証
データ操作 Firestore・Realtime Database へのアクセス(ルール適用) 制限なしで DB 管理・操作
プッシュ通知 クライアントから通知を受け取る FCM(Firebase Cloud Messaging)で通知送信が可能
適用事例 アプリのフロントエンドでのデータ取得・操作 バックエンドでの管理業務・バッチ処理

今回はfirebase-adminを使用します。
公式ドキュメント

合わせて@nestjs/configもインストールします。
@nestjs/config は NestJS で環境変数や設定ファイルを管理するための公式パッケージです。
アプリケーションの設定を 環境変数 (.env) や 設定ファイル から簡単に読み込めるようになります。

npm install firebase-admin --save
npm install @nestjs/config

次にルートディレクトに.envを作成し、firebase web設定で取得をした
secret.keyの中身を見て以下の箇所を書き換えます。

FIREBASE_PROJECT_ID=
FIREBASE_CREDENTIALS=
FIREBASE_CLIENT_EMAIL=

次にsrc/common/firebaseのディレクトリを作成し、その配下に
service.tsとmodule.tsを作成します。

module.ts
import { Module } from '@nestjs/common';
import { FirebaseService } from './service';

@Module({
  providers: [FirebaseService],
  exports: [FirebaseService],
})
export class FirebaseModule {}


service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as admin from 'firebase-admin';

@Injectable()
export class FirebaseService {
  private firebaseAdmin: admin.app.App;

  constructor(private readonly configService: ConfigService) {
    const projectId = this.configService.get<string>('FIREBASE_PROJECT_ID');
    const clientEmail = this.configService.get<string>('FIREBASE_CLIENT_EMAIL');
    const privateKey = this.configService
      .get<string>('FIREBASE_CREDENTIALS')
      ?.replace(/\\n/g, '\n');

    this.firebaseAdmin = admin.initializeApp({
      credential: admin.credential.cert({
        projectId,
        clientEmail,
        privateKey,
      }),
    });
  }

  get admin() {
    return this.firebaseAdmin;
  }
}


api作成

ここからはルートにあるapp.module,service,controllerを使用して
firestoreにinsertするapiを作成しましょう。

まずはapp.moduleで先ほど作成したModuleをimportします。

app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { FirebaseModule } from './common/module/firebase/module';
import { ConfigModule } from '@nestjs/config';
@Module({
  imports: [
    // isGlobal: trueは、このConfigModuleをアプリケーション全体で利用可能にするフラグです。
    // trueに設定すると、他のモジュールでConfigModuleをインポートする必要がなくなります。
    ConfigModule.forRoot({ isGlobal: true, envFilePath: ['.env'] }),
    FirebaseModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}


次にコントローラでエンドポイントを定義します。
今回は仮ですがtodoInsertという名前をGETリクエストで受け付けるようにしました。

app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

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

  @Get()
  todoInsert() {
    return this.appService.todoInsert();
  }
}

次はserviceです。仮ですのでGETリクエストが/に来たら
用意したjsonをtodosコレクションにinsertします。

app.service.ts
import { Injectable } from '@nestjs/common';
import { FirebaseService } from './common/module/firebase/service';

@Injectable()
export class AppService {
  constructor(private readonly firebase: FirebaseService) {}

  async todoInsert(): Promise<string> {
    try {
      const todoData = {
        title: 'Sample TODO',
        description: 'This is a sample TODO item.',
        createdAt: new Date(),
        completed: false,
      };

      const docRef = await this.firebase.admin
        .firestore()
        .collection('todos')
        .add(todoData);

      return `TODOが追加されました: ${docRef.id}`;
    } catch (error) {
      console.error('TODOの追加に失敗しました:', error);
      return 'TODOの追加に失敗しました';
    }
  }
}


動作確認

ご自身のAPIクライアントツールから
localhost:3000/に対してGETリクエストで送信してください。

実際にfirestoreに登録されているかを確認します。

登録することができました🥹

まとめ

今回はNest.jsとfirestoreを連携させる部分について解説をしました。
個人開発の味方であるfirestoreを使ってたくさんアプリを作っていきたいと思います!!

Discussion