🔥
Next.js の API で firestore と エミュレータを使って開発する方法
はじめに
Next.js の API routes で firestore(firebase-admin) と Firestore Emulator を使用して開発をする方法について書きます。
こちらに記述してる内容も前提になってるので、よろしければこちらもご参照ください。
準備
firebase CLI のインストールと init
を参考にインストールと 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
についてはこちら
環境変数
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,
});
}
おまけ
監査ログを有効化することで、firestore のログを見ることができるようになるので、やっておきましょう。
おわりに
以上で、Next.js の API routes で firestore & Firebase Emulator を使用することができます。
参考
記事内で出てきたもの
記事に出てきていないもの
firebase-admin の初期化方法
Cloud Firestore のドキュメント
Discussion