GAE/Go1.11試行（その４：「CloudSQL接続方法」）

# お題
[前回](https://qiita.com/sky0621/items/c7b196a1ba0e126cc3f5)の記事で提示したソースにコメントは書いていたのだけど、ちょっとハマったので別途記事にしておこう。

# GAE試行Index
- [GAE/Go1.11試行（その３：「GoでMVC+S構成のWebAPIを作る」）](https://qiita.com/sky0621/items/c7b196a1ba0e126cc3f5)
- [GAE/Go1.11試行（その2：「"google.golang.org/appengine"パッケージのappengineから取れる情報」）](https://qiita.com/sky0621/items/0e0a119f9fefc40e2953)
- [GAE/Go1.11試行（その1：「クイックスタート」）](https://qiita.com/sky0621/items/8a42ee24cb417940228c)
- [GAE/Go1.9試行（その0：「クイックスタート」）](https://qiita.com/sky0621/items/6d5541e5fa7d2ac349e7)

# 開発環境
### # OS
```
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="17.10 (Artful Aardvark)"
```

### # Golang
```
$ go version
go version go1.11.2 linux/amd64
```

バージョンの切り替えは[goenv](https://github.com/syndbg/goenv)で行っている。

### # gcloud
```
$ gcloud version
Google Cloud SDK 227.0.0
```

# 前提
- [スタンダード環境](https://cloud.google.com/appengine/docs/the-appengine-environments?hl=ja)での開発とする。
- GCPプロジェクトは作成済み。
- gcloudコマンドインストール済み。

# 実践

## GAE/Goのスタンダード環境におけるCloud SQL接続方法（Go v1.9の場合）

下記によると、「 `【ユーザ名】:【パスワード】@cloudsql(【インスタンス接続文字列】)/` 」。
※インスタンス接続文字列は「 `【プロジェクトID】:【リージョン】:【インスタンス】` 」
https://cloud.google.com/appengine/docs/standard/go/cloud-sql/using-cloud-sql-mysql
上記、データベース名については記載がないのだけど、おそらく「 `【ユーザ名】:【パスワード】@cloudsql(【インスタンス接続文字列】)/【データベース名】` 」。

例えば [gorm](https://github.com/jinzhu/gorm) を使って接続するコードは下記のような感じ。

```go
db, err := gorm.Open("mysql", "testuser:testpass@cloudsql(testproj:asia-northeast1:testinstance)/testdb")
```

これを、同じスタンダード環境ということで Go v1.11 でも同じコードで接続を試みると、下記のように接続エラーとなる。

```
panic: dial cloudsql: unknown network cloudsql

goroutine 1 [running]:
main.main()
	/tmp/staging326508706/srv/main.go:20 +0x380
```

## GAE/Goのスタンダード環境におけるCloud SQL接続方法（Go v1.11の場合）

Go v1.11では下記にあるように、同じスタンダード環境でも v1.9 とはCloud SQLへの接続文字列が異なる。
https://cloud.google.com/appengine/docs/standard/go111/using-cloud-sql#running_the_sample_code

```yaml
runtime: go111

env_variables:
  # Replace INSTANCE_CONNECTION_NAME with the value obtained when configuring your
  # Cloud SQL instance, available from the Google Cloud Console or from the Cloud SDK.
  # For Cloud SQL 2nd generation instances, this should be in the form of "project:region:instance".
  CLOUDSQL_CONNECTION_NAME: INSTANCE_CONNECTION_NAME
```


```go
        　〜省略〜

        var (
                connectionName = mustGetenv("CLOUDSQL_CONNECTION_NAME")

        　　〜省略〜
        )

        　〜省略〜

        if socket == "" {
                socket = "/cloudsql"
        }

        // MySQL Connection, comment out to use PostgreSQL.
        // connection string format: USER:PASSWORD@unix(/cloudsql/)PROJECT_ID:REGION_ID:INSTANCE_ID/[DB_NAME]
        dbURI := fmt.Sprintf("%s:%s@unix(%s/%s)/", user, password, socket, connectionName)
        conn, err := sql.Open("mysql", dbURI)
```

正直、読み解きづらい・・・と自分は感じたのだけど、どうだろう・・・？（コメントに記載されたフォーマットが微妙にコードのフォーマットと異なっていてトラップだし。）

ちなみに、以下のように書くとCloud SQLに接続成功。

```go
db, err := gorm.Open("mysql", "testuser:testpass@unix(/cloudsql/testproj:asia-northeast1:testinstance)/testdb")
```

## ローカルとGAE環境との接続文字列切り替え

ローカルではMySQLにつないでGAE環境ではCloud SQLにつなぎたい場合はこんな感じにするといいかな。

```yaml:[app.yaml]
runtime: go111

env_variables:
  # For Cloud SQL 2nd generation instances, this should be in the form of "project:region:instance".
  CLOUDSQL_CONNECTION_NAME: 【プロジェクトID】:asia-northeast1:testinstance
  CLOUDSQL_USER: testuser
  CLOUDSQL_PASSWORD: testpass
  CLOUDSQL_DATABASE: testdb
```

```go
　〜省略〜

func main()  {
	var (
		connectionName = os.Getenv("CLOUDSQL_CONNECTION_NAME")
		user           = os.Getenv("CLOUDSQL_USER")
		password       = os.Getenv("CLOUDSQL_PASSWORD")
		database       = os.Getenv("CLOUDSQL_DATABASE")
	)
	db, err := gorm.Open("mysql", fmt.Sprintf("%s:%s@unix(/cloudsql/%s)/%s", user, password, connectionName, database))
	if appengine.IsDevAppServer() {
		db, err = gorm.Open("mysql", "testuser:testpass@tcp(127.0.0.1:3306)/testdb?charset=utf8&parseTime=True&loc=Local")
	}
	if err != nil {
		panic(err)
	}
	defer db.Close()

　〜省略〜
```

# まとめ
新しものを試すというのは、こういう（当然なんだけど）英語ドキュメントを臆することなく読む必要があり、
かつ、微妙なドキュメントの読みにくさとの戦いでもある。
いや、自分の読解力を棚に上げていることは重々承知・・・。