前回までのあらすじ
- AppEngine GoでHello,Worldやってみたログ - DRYな備忘録
- 【GCP】AppEngine Goからメールを送りたい - DRYな備忘録
- 【GCP】AppEngine GoからCloudStorage上にファイルをREADしたりWRITEしたり - DRYな備忘録
AppEngineでWebサーバをうごかして、メールを送ったり、CloudStorage(AWS S3みたいなやつ)使ったりできたので、今回はCloudSQL(AWS RDSみたいなやつ)使うのやります。
成果物
参考
- Google Cloud SQL Documentation | Cloud SQL | Google Cloud Platform
- Choosing a Storage Option | App Engine standard environment for Go | Google Cloud Platform
- Using Google Cloud SQL | App Engine standard environment for Go | Google Cloud Platform
- The cloudsql package | App Engine standard environment for Go | Google Cloud Platform <- これ
- cloudsql - GoDoc
ドキュメント読んだ感じ
なんてことはあらへん、ただのMySQLインスタンスで、sql.Open
するときにcloudsql
っていうalias使うだけっぽいやん?
まずダッシュボードからCloudSQLインスタンスを作成
デフォではCloudSQLのセクションが隠れてるような気がするんで、カスタマイズで
このセクションを見えるようにして
※ このとき、AppEngineからCloudSQLへのアクセスは、2nd Generationではできないみたいな記述を見たので、1st Generationの一番安いやつにしました。
インスタンスができたら、今度はデータベースを作成する
準備はオッケー
サンプルを書く
GolangのORMっぽいもののgormが使いやすいと思ってるので、gorm使います。
package cloudsqlx import ( "fmt" "net/http" "os" "strconv" _ "github.com/go-sql-driver/mysql" // _ "google.golang.org/appengine/cloudsql" // 別にいらないぞこれ... なんぞ // 薄いし https://github.com/golang/appengine/blob/master/cloudsql/cloudsql.go "github.com/jinzhu/gorm" "github.com/otiai10/marmoset" ) // User represents model in users table type User struct { ID int Name string `json:"name" gorm:"NOT NULL;UNIQUE"` Age int `json:"age" gorm:"TYPE:int;NOT NULL"` } func init() { projectID := os.Getenv("PROJECT_ID") instanceName := os.Getenv("INSTANCE_NAME") databaseName := os.Getenv("DATABASE_NAME") db, err := gorm.Open("mysql", fmt.Sprintf( "root@cloudsql(%s:%s)/%s", projectID, instanceName, databaseName, )) if err != nil { panic(err) } if !db.HasTable(&User{}) { if err := db.CreateTable(&User{}).Error; err != nil { panic(err) } } marmoset.LoadViews("./views") router := marmoset.NewRouter() router.GET("/", func(w http.ResponseWriter, r *http.Request) { users := []User{} if err := db.Find(&users).Error; err != nil { marmoset.Render(w).HTML("index", map[string]interface{}{"error": err.Error()}) return } marmoset.Render(w).HTML("index", map[string]interface{}{ "users": users, }) }) router.POST("/", func(w http.ResponseWriter, r *http.Request) { user := &User{} user.Name = r.FormValue("name") user.Age, err = strconv.Atoi(r.FormValue("age")) if err != nil { marmoset.Render(w).HTML("index", map[string]interface{}{"error": err.Error()}) return } if err := db.Save(user).Error; err != nil { marmoset.Render(w).HTML("index", map[string]interface{}{"error": err.Error()}) return } users := []User{} if err := db.Find(&users).Error; err != nil { marmoset.Render(w).HTML("index", map[string]interface{}{"error": err.Error()}) return } marmoset.Render(w).HTML("index", map[string]interface{}{ "users": users, }) }) http.Handle("/", router) }
で、良い感じにうごいた
アクセス制限
どこ見てもuserとpasswordを設定する項目が無い… が、AppEngineアプリケーション単位やネットワーク的に制限しているし、ネットワーク的にカスタマイズできるようだ。
ローカル開発はどうすべきか
ローカルで書いてgoapp serve
で動かしてみたら以下のエラーを得た
アクセス制限が基本ネットワーク単位なので、localhostからアクセスできないのはうなずける。じゃあどうすっかというと、
DatabaseのURIをまるまる環境変数にしてしまえば、あとは標準のsql driverの挙動となんら変わらないので、いけるはず、
と思ったんだけど、本番は動くがローカルで動かない。なぜなら、ローカルのDev Serverには環境変数を直接渡せないようだ。
- google app engine - why does os.Getenv("SERVER_SOFTWARE") returns blank string for me? - Stack Overflow
- The Go Development Server | App Engine standard environment for Go | Google Cloud Platform
ということで、けっきょくappengine.IsDevAppServer
を使わざるをえなかった(暫定)
Fix Database URI · otiai10/gcpx@93ff4f0 · GitHub ← そのコミット
雑感
- ローカル開発、もうちょっとうまいことできないだろうか
DRYな備忘録
- 作者: Dan Sanderson,玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2011/01/24
- メディア: 大型本
- 購入: 5人 クリック: 414回
- この商品を含むブログ (27件) を見る
はじめてのGoogle App Engine Go言語編 (I・O BOOKS)
- 作者: 茨木隆彰
- 出版社/メーカー: 工学社
- 発売日: 2012/02
- メディア: 単行本
- クリック: 2回
- この商品を含むブログ (4件) を見る