久しぶりのGAE/go
2017年ぐらいはちょいちょいGAE/goとか触ってたんですが、すっかりご無沙汰になっていました。
久しぶりにgolangやGAE/goを触って楽しいなぁと。
今回の学んだこと
- とりあえずアプリを作ってdeployする
- データストアを使かったローカルでの開発を試す
とりあえずアプリを作ってdeployする
gcloudコマンドをが入ってなかったのでまずは、gcloudをmacにインストールする。
https://cloud.google.com/sdk/docs/?hl=ja#install_the_latest_cloud_tools_version_cloudsdk_current_version
ここから「macOS 64 ビット(x86_64)」のファイルを取得する。
gzを解凍して ./google-cloud-sdk/install.sh
を実行する。
適当にプロジェクトを用意する
$ mkdir ~/src/gihtub.com/polidog/sample-gae
$ cd ~/src/gihtub.com/polidog/sample-gae
app.yamlを用意する
runtime: go113
コードを書く
// main.go
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
http.HandleFunc("/", indexHandler)
port := os.Getenv("PORT")
if port == "" {
port = "8000"
log.Printf("Defaulting to port %s", port)
}
log.Printf("Listening on port %s", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
fmt.Fprint(w, "Hello, World!")
}
デプロイする
$ gcloud app deploy
$ gcloud app browse
データストアを使かったローカルでの開発を試す
Datastoreですかね。。
— Ikeda Daigo (@hogedigo) August 14, 2020
↓でDatastore Emulator動かしておきます。https://t.co/eYQ7KfwN8D
そんで
$(gcloud beta emulators datastore env-init)
で環境変数設定してからアプリをgo runすればいけます。
ローカルで動かすためにエミュレータを入れる
$ gcloud components install cloud-datastore-emulator
環境変数を設定する
$(gcloud beta emulators datastore env-init)
環境変数を削除するときには以下の通り
$(gcloud beta emulators datastore env-unset)
エミュレータの起動
$ gcloud beta emulators datastore start
エミュレータのと本番えの接続の切り替えについて
どうやって切り替えるのかなと思ったら、どうやらdatastore.goで DATASTORE_EMULATOR_HOST
を見て判定している。
GitHub Actions上でGCP Datastoreエミュレータを使ったテストを実行する
コードを書く
基本的には以下の記事を参考にしている。 https://cloud.google.com/appengine/docs/flexible/go/using-cloud-datastore?hl=ja
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"time"
"cloud.google.com/go/datastore"
)
var datastoreClient *datastore.Client
func main() {
ctx := context.Background()
var err error
datastoreClient, err = datastore.NewClient(ctx, "aaaaa")
if err != nil {
log.Fatal(err)
}
http.HandleFunc("/", handle)
port := os.Getenv("PORT")
if port == "" {
port = "8000"
log.Printf("Defaulting to port %s", port)
}
log.Printf("Listening on port %s", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}
func handle(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
ctx := context.Background()
// Get a list of the most recent visits.
visits, err := queryVisits(ctx, 10)
if err != nil {
msg := fmt.Sprintf("Could not save visit: %v", err)
http.Error(w, msg, http.StatusInternalServerError)
return
}
// Record this visit.
if err := recordVisit(ctx, time.Now(), r.RemoteAddr); err != nil {
msg := fmt.Sprintf("Could not save visit: %v", err)
http.Error(w, msg, http.StatusInternalServerError)
return
}
fmt.Fprintln(w, "Previous visits:")
for _, v := range visits {
fmt.Fprintf(w, "[%s] %s\n", v.Timestamp, v.UserIP)
}
fmt.Fprintln(w, "\nSuccessfully stored an entry of the current request.")
}
type visit struct {
Timestamp time.Time
UserIP string
}
func recordVisit(ctx context.Context, now time.Time, userIP string) error {
v := &visit{
Timestamp: now,
UserIP: userIP,
}
k := datastore.IncompleteKey("Visit", nil)
_, err := datastoreClient.Put(ctx, k, v)
return err
}
func queryVisits(ctx context.Context, limit int64) ([]*visit, error) {
q := datastore.NewQuery("Visit").Order("-Timestamp").Limit(10)
visits := make([]*visit, 0)
_, err := datastoreClient.GetAll(ctx, q, &visits)
return visits, err
}
appengine.Main()について
サンプルコードにはappengine.Main()を実行していましたが、これなんのためにあるかわからなかったので、調べてみました。
https://t.co/yiLDPp3fxl
— polidog@PartyHard Inc. (@polidog) August 14, 2020
「https://t.co/GpkmNXrorYパッケージ(Appengine SDK)を引き続き利用できますが、その際にはmainパッケージでappengine.Main() を実行する必要があります。」なるほど。
そもそもAppengine SDK使う必要はなさそうなので、appengine.Main()
は消しときました。
最後に
Stay Homeなお盆で、暇だったので久しぶりのGAE/go触ってみました。
Golangの文法からわからないレベルだったのですが、とりあえずローカルでの開発感触はつかめたのでなにか簡単なサービスは作ってみようかと思います。
最後の最後に
これからgolang始めたい人は、このyoutubeみると良いかと思います!