🔥

Next.js の API で firestore と エミュレータを使って開発する方法

2021/12/12に公開

はじめに

Next.js の API routes で firestore(firebase-admin) と Firestore Emulator を使用して開発をする方法について書きます。

https://zenn.dev/hasehiro0828/articles/8a5212198840cd

こちらに記述してる内容も前提になってるので、よろしければこちらもご参照ください。

準備

firebase CLI のインストールと init

https://firebase.google.com/docs/emulator-suite/connect_and_prototype#locally_initialize_a_firebase_project

を参考にインストールと init を行います。

curl -sL firebase.tools | bash
firebase init

この時、firestore と emulator を有効にします。

サービスアカウントの作成

firebase のコンソールのプロジェクトの設定 > サービスアカウント から、Firebase Admin SDK の秘密鍵を生成し、ダウンロードされた json を Next のプロジェクトルートに置きます。

firebase-admin のインストール

yarn add -D firebase-admin

package.json の scripts の編集

{
  "scripts": {
    "dev": "FIRESTORE_EMULATOR_HOST=localhost:8080 next dev",
    "run-emulator": "firebase --project='test' emulators:start",
    ...
  },
}

FIRESTORE_EMULATOR_HOSTについてはこちら

https://firebase.google.com/docs/emulator-suite/connect_firestore#admin_sdks

環境変数 FIRESTORE_EMULATOR_HOST が設定されている場合、Firebase Admin SDK は Cloud Firestore エミュレータに自動的に接続します。

コード作成

src/pages/api/lib/firebaseAdmin.ts
import admin from "firebase-admin";

import type { ServiceAccount } from "firebase-admin";

import serviceAccount from "**-firebase-adminsdk-**.json";

if (admin.apps.length === 0) {
  if (process.env.NODE_ENV === "production") {
    admin.initializeApp({
      credential: admin.credential.cert(serviceAccount as ServiceAccount),
    });
  } else {
    // emulator
    admin.initializeApp({
      projectId: "test",
      credential: admin.credential.applicationDefault(),
    });
  }
}

export { admin as firebaseAdmin };
src/types/firestore.ts
import type { firestore } from "firebase-admin";

export interface Doc {
  id: string;
  text: string;
  createdAt: firestore.FieldValue;
}
src/pages/api/addText.ts
import requestIp from "request-ip";

import type { Doc } from "@/types/firestore";
import type { NextApiRequest, NextApiResponse } from "next";

import { LimitChecker } from "@/lib/limitChecker";
import { firebaseAdmin } from "@/pages/api/lib/firebaseAdmin";

const limitChecker = LimitChecker();
const LIMIT_NUMBER = 3;

export interface ReqBody {
  text: string;
}
interface Req extends NextApiRequest {
  body: ReqBody;
}
export interface Res {
  documentId: string | undefined;
}
export default async function handler(req: Req, res: NextApiResponse<Res>): Promise<void> {
  const clientIp = requestIp.getClientIp(req) || "IP_NOT_FOUND";

  try {
    await limitChecker.check(res, LIMIT_NUMBER, clientIp);
  } catch (error) {
    console.error(error);

    res.status(429).json({ documentId: undefined });
    return;
  }

  const documentRef = firebaseAdmin.firestore().collection("/texts").doc();
  const document: Doc = {
    id: documentRef.id,
    text: req.body.text,
    createdAt: firebaseAdmin.firestore.FieldValue.serverTimestamp(),
  };
  documentRef.set(document);

  res.status(200).json({
    documentId: documentRef.id,
  });
}
src/lib/api.ts
import axios from "axios";

import type { ReqBody, Res } from "@/pages/api/addText.page";
import type { AxiosResponse } from "axios";

export class api {
  // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
  static postAddText = async (text: string) =>
    axios.post<Res, AxiosResponse<Res>, ReqBody>("/api/addText", {
      text: text,
    });
}

おまけ

https://qiita.com/kawamou/items/11a05aeeeee40cceb20e

監査ログを有効化することで、firestore のログを見ることができるようになるので、やっておきましょう。

おわりに

以上で、Next.js の API routes で firestore & Firebase Emulator を使用することができます。

参考

記事内で出てきたもの

https://firebase.google.com/docs/emulator-suite/connect_and_prototype#locally_initialize_a_firebase_project

https://github.com/firebase/firebase-tools/issues/2365#issuecomment-749499261

https://firebase.google.com/docs/emulator-suite/connect_firestore#admin_sdks

https://qiita.com/kawamou/items/11a05aeeeee40cceb20e

記事に出てきていないもの

https://github.com/firebase/firebase-admin-node/issues/575#issuecomment-524744793

firebase-admin の初期化方法

https://firebase.google.com/docs/firestore/quickstart?authuser=0#node.js

Cloud Firestore のドキュメント

GitHubで編集を提案

Discussion