GoでMySQL,Redisでアプリケーションを作ってみて詰まったことあれこれ

## はじめに

最近なんか新しい言語に触れてみたい！
そんな欲がだんだんと深まってきていた矢先Goと出会いました。
せっかく欲が出たんならと簡単なアプリ作ってみてデプロイまでをやってみたので、その過程で色々と詰まったことがあったのでそんなことをつらつらと書きます。

## 構成

 - Go (1.10)
   - 依存関係管理ツール : [dep](https://github.com/golang/dep) 
   - フレームワーク: [labstack/echo](https://github.com/labstack/echo)
   - ORM : [jinzhu/gorm](https://github.com/jinzhu/gorm)
   - DBドライバ : [go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
   - バリデーション : [go-playground/validator](https://github.com/go-playground/validator)
   - 認証 : [satori/go.uuid](https://github.com/satori/go.uuid) + [golang/crypto/bcrypt](https://github.com/golang/crypto)
   - セッション : [boj/redistore](https://github.com/boj/redistore) + [soveran/redisurl](https://github.com/soveran/redisurl)
 - Redis
 - mysql(5.7)
 - docker-compose
 - heroku

## 出来たもの

:octocat: [gtongy/demo-echo-app](https://github.com/gtongy/demo-echo-app)
:computer: [demo app by echo](https://frozen-bayou-84658.herokuapp.com)

## 詰まったこと

### :question:作業場所わからん。どこに置いたらいいのか

「[GOPATH は適当に決めて問題ない - Qiita](https://qiita.com/yuku_t/items/c7ab1b1519825cc2c06f)」と「みんなのGo言語」を参考。
``export GOPATH=$HOME/go_work``
home directory配下にgo_workというディレクトリを作ってその下に

```
.
├── bin
├── pkg
└── src
    └── github.com
        └── gtongy
            └── demo-echo-app
```
のように配置して実装を行った。作業ディレクトリの下は

 - bin
    - go getでインストールされた実行形式のファイルの置き場所
 - pkg
    - パッケージオブジェクトの置き場所
 - src
    - ソースコードが記述された置き場所。ここで主に作業を行う。

となってます。

### :question:テンプレートってどう呼び出す？

ほとんど[公式](https://echo.labstack.com/guide/templates)通り。
Renderにデータ付きのテンプレートを食わせてやると、ステータスコード付きのresponseを返してくれる。
``template.Must(template.ParseGlob("templates/*.tpl"))``でtplファイルのパース時のerrが起こった時にpanicを起こすようにするラッパーを介してEcho.Contextにtplファイルを入れ込んでhandler側でごにょごにょすると画面にテンプレートを描画できる。

```go
// テンプレート描画用の構造体
type TemplateRenderer struct {
	templates *template.Template
}

// データ食わせてテンプレートを表示させるとこ
func (t *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
	return t.templates.ExecuteTemplate(w, name, data)
}

func main() {
  renderer := &TemplateRenderer{
    templates: template.Must(template.ParseGlob("templates/*.tpl")),
  }
  e.Renderer = renderer
  c.GET("/login", c.Render(http.StatusOK, "form",   map[string]interface{}{
		"csrfToken": csrfToken,
  }))
}
```
ちなみに、テンプレート側で共通のファイルとかあるけど、それもはじめに全て使用分のテンプレートをRenderしておけば呼び出しも比較的楽に出来た。

### :innocent: あれ...自分で作った他packageの関数とかメソッド参照出来ないんだけど...

Go言語のアクセス許可のこと何にもわかってなかったためつまづいた。
パッケージ外へのアクセスを許可させる時は関数なりメソッドの先頭を大文字にしないと参照が出来ない。
地味にここで呼び出しが出来なくてハマって辛い。
以下の記事に巡り合って解決したので感謝です。

[Go言語での構造体実装パターン · THINKING MEGANE](http://blog.monochromegane.com/blog/2014/03/23/struct-implementaion-patterns-in-golang/#エクスポートによるアクセス許可:0cfff44c5c402a0dd8247248dcfe385d)

### :innocent: んん...?gormでmysqlをSELECTする時にScan error出てきたぞ...

以下記事がまさにその問題で助かりました :bow:

[Golangで`Scan error`が出た時の対応 - Qiita](https://qiita.com/kotamat/items/e6dd5806e52939d28043)
Scanするときの時間の型とstructの型が違うことでエラーを吐いてたみたい。

### :question: Redisがローカルで動くのはいいけど、herokuでどうRedis参照させたらいいんだろう？

[こちらの記事](https://blog.leko.jp/post/introduction-of-golang#heroku)を参考にさせていただきました :bow:

ローカルで開発する時はNewRediStoreで接続してたんですが、herokuの設定がURLの形式で吐き出されるのを変換するところでハマりました。
記事の通りですが、NewRediStoreで接続していたところをNewRediStoreWithPoolで接続させれるようにするために、内部でredis.Conn => redis.Poolに変換させてNewRediStoreWithPoolでインスタンスを生成させるようにしています。

### :question: そういえばsessionってどうやって破棄するんだ？

有効期限切れの設定をセッションに上書きして保存させることで破棄。

```go
session.Options = &sessions.Options{MaxAge: -1, Path: "/"}
session.Save(c.Request(), c.Response())
```
[go - gorillaでセッションを破棄（削除）する方法を知りたい - スタック・オーバーフロー](https://ja.stackoverflow.com/questions/20326/gorillaでセッションを破棄-削除-する方法を知りたい)
[build-web-application-with-golang/06.2.md at master · astaxie/build-web-application-with-golang · GitHub](https://github.com/astaxie/build-web-application-with-golang/blob/master/ja/06.2.md)

## まとめ

様々な記事に助けられ色々とつまづきはしましたが、Goの入門の壁を叩いてみました。
言語自体はすごくシンプルだけど型もある程度の縛りはもうけられているのが安心感も強いなと感じました。そして何よりも実行速度の速さが驚き。
それと抽象的な構造を先に決めておいてその振る舞いを構造体にメソッドとして生やしていく感覚がコード書いてる時は楽しかったりもしていて。
感想をあげだすと結構ポジティブな印象が強い言語で個人的にはハマりそうな予感を感じていました。
入門として入ってみるとなかなか面白い言語だと思うので、これから新しくどんな言語学ぼうかなーって悩んでる人は選択肢の一つとしてGoで遊んでみてもいいかも。

## 参考文献

 - [Echo - High performance, minimalist Go web framework](https://echo.labstack.com)
 - [Goに入門してRedis+PostgresなアプリをHerokuにデプロイするまで | WEB EGG](https://blog.leko.jp/post/introduction-of-golang)
 - [go - Goのテンプレートのif文で表示を分けたい](https://ja.stackoverflow.com/questions/16287/goのテンプレートのif文で表示を分けたい)
 - [GitHub - scotch-io/go-echo-vue-single-page-app: A Todo example written in Go, using the Echo framework and Vue](https://github.com/scotch-io/go-echo-vue-single-page-app)
 - [GoでMySQLに接続する - Qiita](https://qiita.com/taizo/items/54f5f49c6102f86194b8)
 - [BCryptのすすめ - Qiita](https://qiita.com/ponkotuy/items/1a703b866ddf5c9fe80c)
 - [【東京・千代田区｜システム開発】株式会社ユニトラスト |  - 【Go】echoフレームワークでログイン機能を作成する
](https://www.unitrust.co.jp/【go】echoフレームワークでログイン機能を作成する/)
 - [Go言語からGORMとECHOでJSONを返すAPIサーバー作ってみる。 - OngaLog](http://onga-tec.hatenadiary.jp/entry/2016/08/12/010938)
 -  [golang+EchoでREST APIを作った話 - なみひらブログ](http://namihira.hatenablog.com/entry/20170409/1491710093)
 - [Go言語のエラーハンドリングについて - Qiita](https://qiita.com/nayuneko/items/3c0b3c0de9e8b27c9548)
 - [Best Practices for API Error Handling | Nordic APIs |](https://nordicapis.com/best-practices-api-error-handling/)
 - [echoのAPIサーバ実装とエラーハンドリングの落とし穴 - Qiita](https://qiita.com/usk81/items/5f2bcfe06eb83830ee55)