概要
Firestoreのエミュレータ構築は gcloud CLIを使う方法 と Firebase CLIを使う方法 があります。
どちらを使ってもよいのですがFirebase CLIを使う場合は、ブラウザ上でFirestoreのUIが使えるため、開発効率が上がりそうです。
ということでFirebase CLIでの構築をしていきます。
こんな人向け
- CLIをローカル環境に入れたくない(Dockerを使いたい)
- FirestoreにGoで読み書きをしたい
- デプロイは特に考えず、お手軽にFirestoreの動作確認ができる環境を作りたい
環境構築
Dockerfileの設定
Firebaseエミュレータコンテナ用
Emulator Suite をインストールする前に、以下が必要です。
- Node.js バージョン 16.0 以降
- Java JDK バージョン 11 以降
公式ドキュメントによると、Firebaseエミュレータを使うには NodeとJavaが必要 とのことなので、nodeコンテナにJavaをインストールしました。
ついでにnpmでFirebase CLIをインストールしておきます。
FROM node:20.10.0-slim
RUN apt-get -y update && apt-get -y install default-jdk
RUN npm install -g firebase-tools
Goコンテナ用
Goのアプリケーション用のコンテナです。
1行なので、わざわざDockerfileにすることもないですが、開発を進めていくと色んなパッケージをイメージに入れておきたくなるのでDockerfileにしてます。
個人の好みで必要なパッケージをインストールしましょう。
FROM golang:1.21
Firebaseの設定
エミュレータを動かすのに必要なファイルは下記の2つです。
.firebaserc
firebase.json
まずは.firebaserc
です。
エミュレータ用なのでプロジェクト名は何でもOKです。
{
"projects": {
"default": "test-project"
}
}
次にfirebase.json
ですが、Dockerで使用する場合は"host": "0.0.0.0"
を指定しないとdocker-composeでポートフォワードしてもブラウザで確認できないようです。
公式ドキュメントのこの辺の記載が該当しそうです。
デフォルトでは、エミュレータは localhost からのリクエストにのみ応答します。つまり、ホストされているコンテンツには同じパソコンのウェブブラウザからアクセスできますが、ネットワーク上の他のデバイスからはアクセスできません。
{
"emulators": {
"singleProjectMode": false,
"ui": {
"host": "0.0.0.0",
"port": 4000
},
"firestore": {
"host": "0.0.0.0",
"port": 8080
}
}
}
これらのファイルはfirebase login
をしてfirebase init
によるプロジェクト初期化設定を進めていくと自動で作成されます。
今回はFirestoreのエミュレータだけの構成なので事前に作ってバインドしますが、別のサービス(Authentication
, Cloud Functions
など)を使ったり複雑な構成にする場合は、事前に作るの大変なので自動作成するのが良いかと思います。
またfirebase init
による初期化時に「Firestoreを使用する」選択をした場合は、下記のファイルも自動で作成されます。
firestore.indexes.json
firestore.rules
今回はデプロイは特に考えず、開発環境だけ作りたいので firestore.indexes.json
, firestore.rules
は不要です。
docker-composeの設定
Firestoreエミュレータに接続するのに、接続する側はFIRESTORE_EMULATOR_HOST
を環境変数に設定しておく必要があるので忘れず設定しておきます(公式ドキュメント)。
version: '3.9'
services:
app:
tty: true
build:
context: .
dockerfile: ./app/Dockerfile
environment:
FIRESTORE_EMULATOR_HOST: "firebase:8080"
volumes:
- ./:/workspace
working_dir: /workspace
firebase:
build:
context: .
dockerfile: ./firebase/Dockerfile
ports:
- 4000:4000
volumes:
- ./firebase/.firebaserc:/firebase/.firebaserc
- ./firebase/firebase.json:/firebase/firebase.json
tty: true
working_dir: /firebase
command: firebase emulators:start
Goサンプルコードの作成
Firebase側のドキュメントではFirebaseのクライアントライブラリとしてfirebase.google.com/go
を使用しています。
GCP側のドキュメントではFirestoreのクライアントライブラリとしてcloud.google.com/go/firestore
を使用しています。
firebase.google.com/go
のドキュメントによると、firebase.google.com/go
はFirestoreクライアントインスタンスを作るのにcloud.google.com/go/firestore
を使っているため、Firestoreだけを使うのであれば後者だけインストールしておけばOKです。
Firestore returns a new firestore.Client instance from the https://godoc.org/cloud.google.com/go/firestore package.
package main
import (
"context"
"log"
"cloud.google.com/go/firestore"
)
func main() {
ctx := context.Background()
client := createClient(ctx)
defer client.Close()
createSample(ctx, client)
}
func createClient(ctx context.Context) *firestore.Client {
projectID := "test-project"
client, err := firestore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
return client
}
func createSample(ctx context.Context, client *firestore.Client) {
_, _, err := client.Collection("users").Add(ctx, map[string]interface{}{
"first": "Ada",
"last": "Lovelace",
"born": 1815,
})
if err != nil {
log.Fatalf("Failed adding alovelace: %v", err)
}
}
サンプルコードはクイックスタートのものを拝借しました。
確認
dockerを立ち上げてGoのサンプルコードを実行してFirestoreのUI上で、サンプルユーザーが追加されることを確認します。
# コンテナ起動
docker compose up -d
# ログ確認してエミュレータの起動を確認
docker compose logs
上のようなログが出ていれば無事Firebaseのエミュレータが起動できてるので、ブラウザで http://localhost:4000 にアクセスしてエミュレータUIを確認しましょう。
エミュレータの起動には少し時間がかかるのでコンテナが異常終了してなければ少し待ってみるといいです。
続いてGoの初期設定をしてから、サンプルコードを実行してFirestoreエミュレータにデータが登録されることを確認します。
# モジュール初期化
docker compose exec app go mod init firestore-test
# クライアントライブラリインストール
docker compose exec app go get cloud.google.com/go/firestore
# サンプルコード実行
docker compose exec app go run main.go
http://localhost:4000/firestore にアクセスしてみましょう。
処理が完了すれば以下のようにFirestoreエミュレータにサンプルデータが登録されます。
まとめ
複雑なデータ構造になってくると、データを確認したいときにデータ構造を加工して読みやすい形にして出力する必要が出てくると思います。
FirestoreのUI上で構造を確認できた方が直感的に理解できるので効率的に作業を進められるでしょう。