概要
まだGCP上で既存プロジェクトを扱う際にはDataStoreをそのまま使うということも多いけど、新しいプロジェクトを作成する際にはやっぱりFirestoreを使っていきたいよねー。
そんなわけで、構築&動作確認をした際のメモ書きです。
参考:
Go + Firestore (サーバー側) でローカルエミュレーターを使ってテストする
https://qiita.com/castaneai/items/c7d68cbee1a6e3655247
開発環境
環境は以下の通りです。
- Mac OSX(10.14.5)
- Golang 1.9
- Echo 3.1.0
- AppEngine 1.6.1
環境構築編
gcloud componentsのアップデート
あまり調べてないけど、ぼくが入れていたgcloudのバージョンでは対応してなかったので、コンポーネントの更新を行いました。
$ gcloud components update
Your current Cloud SDK version is: 206.0.0
You will be upgraded to version: 253.0.0
┌─────────────────────────────────────────────────────────────────────────────┐
│ These components will be updated. │
├─────────────────────────────────────────────────────┬────────────┬──────────┤
│ Name │ Version │ Size │
├─────────────────────────────────────────────────────┼────────────┼──────────┤
│ App Engine Go Extensions │ 1.9.70 │ 56.4 MiB │
│ BigQuery Command Line Tool │ 2.0.44 │ < 1 MiB │
│ BigQuery Command Line Tool (Platform Specific) │ 2.0.34 │ < 1 MiB │
│ Cloud SDK Core Libraries │ 2019.06.28 │ 11.0 MiB │
│ Cloud SDK Core Libraries (Platform Specific) │ 2018.09.24 │ < 1 MiB │
│ Cloud Storage Command Line Tool │ 4.39 │ 3.6 MiB │
│ Cloud Storage Command Line Tool (Platform Specific) │ 4.34 │ < 1 MiB │
│ gRPC python library │ 1.20.0 │ 1.9 MiB │
│ gcloud Beta Commands │ 2019.05.17 │ < 1 MiB │
│ gcloud app Python Extensions │ 1.9.86 │ 6.0 MiB │
│ gcloud cli dependencies │ 2019.05.03 │ 2.4 MiB │
│ gcloud cli dependencies │ 2018.08.03 │ 1.5 MiB │
└─────────────────────────────────────────────────────┴────────────┴──────────┘
┌───────────────────────────────────────────────┐
│ These components will be installed. │
├──────────────────────────┬─────────┬──────────┤
│ Name │ Version │ Size │
├──────────────────────────┼─────────┼──────────┤
│ Cloud Datastore Emulator │ 2.1.0 │ 18.4 MiB │
└──────────────────────────┴─────────┴──────────┘
A lot has changed since your last upgrade. For the latest full release notes,
please visit:
https://cloud.google.com/sdk/release_notes
Do you want to continue (Y/n)? Y
# あとは省略
goappを使えるようにする
gcloudを更新すると、Macだとだいたいgoappが使えなくなっちゃいます。
(本当は goapp
をやめてgcloudで完結させたいんだけど、面倒だから今もgoappでローカル検証 + deployしてます)
$ goapp serve app-sandbox.yaml
-bash: /Users/xxx/tools/google-cloud-sdk/platform/google_appengine/goapp: Permission denied
こんな感じにエラーになっちゃうので、いつものように権限を通します。
$ sudo chmod +x ~/tools/google-cloud-sdk/platform/google_appengine/goapp
# 使えるようになったことを確認
$ goapp
Go is a tool for managing Go source code.
Usage:
goapp command [arguments]
The commands are: (省略)
firestore emuratorを起動
はじめて使う場合、エミュレーターがダウンロードされます。
今後はローカルで検証する際には毎回 firestoreのエミュレーターを起動することになるみたい。
$ gcloud beta emulators firestore start
You need the [cloud-firestore-emulator] component to use the Google
Cloud Firestore emulator.
Your current Cloud SDK version is: 253.0.0
Installing components from version: 253.0.0
┌───────────────────────────────────────────────┐
│ These components will be installed. │
├──────────────────────────┬─────────┬──────────┤
│ Name │ Version │ Size │
├──────────────────────────┼─────────┼──────────┤
│ Cloud Firestore Emulator │ 1.6.0 │ 41.1 MiB │
└──────────────────────────┴─────────┴──────────┘
For the latest full release notes, please visit:
https://cloud.google.com/sdk/release_notes
Do you want to continue (Y/n)? Y
╔════════════════════════════════════════════════════════════╗
╠═ Creating update staging area ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: Cloud Firestore Emulator ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Creating backup and activating new installation ═╣
╚════════════════════════════════════════════════════════════╝
Performing post processing steps...done.
Update done!
Restarting command:
$ gcloud beta emulators firestore start
Executing: /Users/xxx/tools/google-cloud-sdk/platform/cloud-firestore-emulator/cloud_firestore_emulator start --host=::1 --port=8915
[firestore] API endpoint: http://::1:8915
[firestore] If you are using a library that supports the FIRESTORE_EMULATOR_HOST environment variable, run:
[firestore]
[firestore] export FIRESTORE_EMULATOR_HOST=::1:8915
[firestore]
[firestore] Dev App Server is now running.
実際に動かしてみる
yamlファイルの修正
FIRESTORE_EMULATOR_HOST の定数を入れろということなので、 yamlファイルに以下のように記載。
application: testProject
module: default
version: 1
runtime: go
api_version: go1.9
threadsafe: true
handlers:
- url: /.*
script: _go_app
skip_files:
- (.*/)?vendor/(.*/)?
- (.*/)?golang\.org/(.*/)?
- (.*/)?pkg/(.*/)?
automatic_scaling:
max_concurrent_requests: 40
min_idle_instances: 0
max_idle_instances: 1
max_pending_latency: automatic
min_pending_latency: 3000ms
env_variables:
FIRESTORE_EMULATOR_HOST: "localhost:8915" # 追加
動作確認
とりあえずは動けばいいレベルで。
GET /debug
を叩くと登録され、 GET /debug/{id}
を叩くとそのIDのものが取得できるだけのやつ。
import (
"context"
"github.com/labstack/echo"
"google.golang.org/appengine/log"
"google.golang.org/appengine"
"net/http"
"project/app/core"
"project/app/handler"
"github.com/gorilla/sessions"
"github.com/labstack/echo-contrib/session"
"project/app/middlewares"
"firebase.google.com/go"
"fmt"
)
const AppEngine = "appengine"
var e = createMux()
func init() {
{
ah := e.Group("/_ah")
ah.GET("/start", func(c echo.Context) error { return c.String(http.StatusOK, "") })
}
g := e.Group("/debug")
g.GET("", func(c echo.Context) error {
ctx, ok := c.Get(AppEngine).(context.Context)
if !ok {
return c.String(http.StatusInternalServerError, "error")
}
app, err := firebase.NewApp(ctx, nil)
if err != nil {
return c.String(http.StatusInternalServerError, fmt.Sprintf("failed (reason: %+v)", err))
}
store, err := app.Firestore(ctx)
if err != nil {
return c.String(http.StatusInternalServerError, fmt.Sprintf("failed (reason: %+v)", err))
}
doc, _, err := store.Collection("users").Add(ctx, map[string]interface{}{
"name": "hello",
});
if err != nil {
return c.String(http.StatusInternalServerError, fmt.Sprintf("failed (reason: %+v)", err))
}
return c.String(http.StatusOK, fmt.Sprintf("DocID: %s", doc.ID))
});
g.GET("/:id", func(c echo.Context) error {
ctx, ok := c.Get(AppEngine).(context.Context)
if !ok {
return c.String(http.StatusInternalServerError, "error")
}
app, err := firebase.NewApp(ctx, nil)
if err != nil {
return c.String(http.StatusInternalServerError, fmt.Sprintf("failed (reason: %+v)", err))
}
store, err := app.Firestore(ctx)
if err != nil {
return c.String(http.StatusInternalServerError, fmt.Sprintf("failed (reason: %+v)", err))
}
dsnap, err := store.Collection("users").Doc(c.Param("id")).Get(ctx)
if err != nil {
return c.String(http.StatusInternalServerError, fmt.Sprintf("failed (reason: %+v)", err))
}
return c.String(http.StatusOK, fmt.Sprintf("DocID: %+v", dsnap.Data()));
})
}
func UseAppEngine() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
ctx := appengine.NewContext(c.Request())
c.Set(AppEngine, ctx)
return next(c)
}
}
}
func createMux() *echo.Echo {
e := echo.New()
e.Use(core.UseAppEngine())
http.Handle("/", e)
return e
}
GET /debug を叩く
GET /debug/:id を叩く
なるほどねー。
所感
導入自体は特に何もつまるところはなかったです。 firestoreのAPIの学習はこれからなのでよくわかってないです(´・_・`)
一応 DataStoreと互換性あるって話だけど、 goon は使えないんだろうなぁ。