Docker環境を構築し、Golang Echo v5-alphaでJWT Token認証 ホットリロード、リモートデバッグ、マイグレーション、GormのORMが入ったフルスタックフレームワークチックな環境の構築をした

docker環境を構築し、
Go言語のフレームワークのechoフレームワークに、
JWT Token認証 ホットリロード、リモートデバッグ、マイグレーション、
GormのORMと色々入ったフルスタックフレームワークチックな環境の構築をしてみました。

今回の記事は、この記事の作成の為に公開しました、gihubのソースの動かし方の説明になります。
※githubのソースは記事の一番下になります。

記事の評判がよければ、ライブラリーの比較や説明、ソースコードの説明等記事を更新するかもしれません。

※ validation、テストは入っておりません。
あと、errorハンドリングやlog出力等できていないです。

この記事は、golang初心者やechoフレームワークをこれから学ぶ人向けとなります。
自分は、golangの学習を初めて時間があまり経っていないので、少し説明やソースコードに粗がありますが、ご容赦ください

あと、元々echo v4で作っていたのを、echo v5-alphaに書き換えているので、
v5-alphaの作法に書き変わっていない部分があります。

今回詰まった点は下記の記事に載せております。

https://qiita.com/shingo02/items/eb1ab342dbad01759f4b

---
Golangを始めた理由は、phpに飽きてきたのと
LaravelやRailsといった動的型付け言語のフルスタックフレームワークは、
すこぶる実行速度が遅いという理由です。

laravelでいうとEloquentが機能の中で一番遅い為、build queryやPDOといった物で代用したりするケースもありますが、
個人的にそこまでするのであれば、そもそも使わない方が良いのではと思います。
そもそも便利なModelや認証自体自作しないといけなくなり苦行です。
また、そこまでしてもベースが遅いのでそこまでする意味がありません

あと、動的型付け言語はDDDといった設計との相性も良くないといわれており
設計をこだわるなら初めからScalaといった言語を選定すれば良いと思ってしまいます。

https://zenn.dev/nameless_gyoza/articles/e30d9e1283ab5b9576ff

---

echoフレームワーク選定理由なのですが、
Go言語のフレームワーク中で軽量かつ一番高速に動く為です。

小規模〜中規模までのシステムや
マイクロサービス化のbackendに使用するならechoが良さそうです。

他のフレームワークもかなり悩んだのですが、やはり、高速で動くという点に
心動かされました。

---

何故、この記事とgithubのリポジトリーを公開したのか？
なのですが、自分も含め、ehcoをインストールすると下記のキャプチャーのように
2ファイル、go.mod、go.sumしかインストールされず、初学者には実装イメージも掴めずハードルが高いと思ったからです。

あと、Laravelみたいに、マイグレーションやEloquentみたいにSQLを書かなくてもDB操作ができたりし
少しでも、簡単に開発できるようにしたかったからです。
あと、echoは、Apiサーバー用に使われすのが普通なので、JWT token必須なので導入しました。

ちなみgo.mod、go.sumの説明なのですが、
phpのcomposerでいうと、go.modがcomposer.json、go.sumがcomposer.lockにあたり、
nodeでいうと、go.modがpackage.json、go.sumがyarn.lockやpackage-lock.jsonになります。

余談になりますが、Go言語のパッケージ管理なのですが、
色々短期間に変更されているみたいで、
現在は、Go Modulesが一般的です。

モジュールのインストール方法は、`go get`だったのですが、
Go1.18 からは、`go install`に完全に切り替わります。

goのDockerfileも`go get`から`go install`に書き換えております。

go get
```
RUN go get github.com/pilu/fresh
```
go install
```
RUN go install github.com/pilu/fresh@latest
```

違いは、`go get`はバージョンを指定できなかったのに対し、
`go install`はバージョンを指定する必要があります。

`go install github.com/ライブラリー@バージョン`

となります。

https://qiita.com/eihigh/items/9fe52804610a8c4b7e41

https://nishinatoshiharu.com/go-modules-history/


※ 下記はecho v4 インストール直後のフォルダ構成
![スクリーンショット 2022-06-16 1.44.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981122/6958e6d1-d128-15a5-6a2f-6dbff77a9923.png)

ではどういう風に学習していったかというと
echoで既に組まれたサンプルを落とし、自分で肉付けしてイメージをつけていきました。
参考にさせて頂きました記事はこちらになります。
オニオンアーキテクチャーかクリーンアキテクチャーで迷ったのですが、
設計に詳しくないですが、あまり変わらないということなので、
オニオンアーキテクチャーを選択しました。

https://qiita.com/nanamen/items/f37d1047368929e377fd

こちらは、goのライブラリー管理が「Gopkg.toml」と「Gopkg.lock」で古かったり
一部のライブラリーの開発が終了していたりしていた為、
再度ライブラリー選定し入れ直したりしております。

---

利用ライブラリー

go-sql-driver

https://github.com/go-sql-driver/mysql

golang-jwt

https://github.com/golang-jwt/jwt

golang-migrate

https://github.com/golang-migrate/migrate

jinzhu/gorm

https://github.com/jinzhu/gorm

上記を使っていますが、
下記が公式のgormになります。恐らく下記を使った方が良いかもしれません。
※ jinzhu/gormは、公式gormをforkして作られています。

※ go-gorm/gorm

https://github.com/go-gorm/gorm

spf13/viper

https://github.com/spf13/viper


---

公開リポジトリーの動かし方

一番最後のリポジトリをgit cloneした後、docker-compose.ymlのtargetを任意のものに
変更してください、target prodとdevはコメントアウトしている為、
そのままdockerを立ち上げるとホットリロード + リモートデバッグ環境になります。
必ずどれかひとつのみ設定してください。

docker-compose.yml
```
services:
  back:
    build:
      context: .
      dockerfile: app/Dockerfile #Dockerfileの場所
      # target: prod    # 本番用
      # target: dev     # 開発用(ホットリロード)
      target: dev-debug # 開発用(ホットリロード + リモートデバッグ)
    volumes:
```

上記を編集後、

```
docker-compose up -d
```

を行いdockerを立ち上げてください。

```
※ docker ps で起動中コンテナ確認
docker exec -i -t echo-backend-v5-alpha_back_1 sh
```

でechoの置いてあるコンテナに移動し、

その後、dbフォルダに移動し
```
cd /go/src/app/db
```

下記のコマンドでマイグレーションの実行を行なってください、
テーブルが自動で生成されます。
```
go run migrate.go -exec up
```

マイグレーションなのですが、下記の方の記事の方法を参考に動かない部分は直しほぼそのまま使っております。

https://qiita.com/tanden/items/7b4fb1686a61dd5f580d#golang-migratemigrate%E3%81%A8%E3%81%AF

※ /go/src/appにgo.sumが生成されていなければ、
下記を実施しgo moduleをインストールしてください
恐らくdockerを立ち上げると生成されていると思います。
```
go mod tidy

もしくは

go get
```
---
デバッグ設定

Goland

下記の用に、Debug Configurationsの設定をこなってください

![スクリーンショット 2022-06-17 0.22.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981122/f9ce9310-dfb8-bae0-cf18-2e427cd6e416.png)

Visual Studio Code

下記を参考に拡張機能をインストール後、リポジトリーをcloneしたら
.vscode/launch.jsonを用意していますので、こちらを読み込んでください。

https://qiita.com/momotaro98/items/7fbcad57a9d8488fe999


![スクリーンショット 2022-06-17 0.26.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981122/8d22f9f6-afc2-e35e-07e2-21530409bace.png)

---

起動確認

上記手順まで行い下記の、URLにアクセスすると
起動しません。

http://localhost:5566/

![スクリーンショット 2022-06-17 0.33.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981122/3c1f8443-1fc8-d1d5-0044-9852738abb0f.png)

docker-compose.yml の下記のtargetをdev-debugで立ち上げると
そのままアクセスしても、うまく動きません、
target: devや、target: prodで立ち上げるとそのまま開きます。

こちらは、マルチステージングビルドになり、
Dockerfileのどのコンテナを使うか指定しています。

マルチステジーングビルドとは、
デプロイするなら、軽量なOSでビルドされた物だけを、
開発で使うのであれば、リモートデバッグやリアルタイムでコンパイルできるホットリロード環境が入った物など
用途によってどのコンテナを使うか選ぶことができます。
マルチステジーングビルドを使わないと環境ごとに、Dockerfileを用意しないといけないので、
大変便利です。

https://docs.docker.jp/develop/develop-images/multistage-build.html


```
services:
  back:
    build:
      context: .
      dockerfile: app/Dockerfile #Dockerfileの場所
      # target: prod    # 本番用
      # target: dev     # 開発用(ホットリロード)
      target: dev-debug # 開発用(ホットリロード + リモートデバッグ)
    volumes:
```

で、ホットリロード + リモートデバッグで立ち上げた場合は、
必ず、エディター上で一度、デバックしてください、
![スクリーンショット 2022-06-17 0.49.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981122/6cf94f79-ac80-7ccc-02c2-e4db426b7441.png)
で、立ち上げたら、ステップ実行やり切るか、リモートデバッグを中断してください、
Golandの場合は、下記のように、Yesを押して中断すると、Debugできなくなるので
注意してください、Visual Studio Codeは大丈夫です。
![スクリーンショット 2022-06-17 0.50.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981122/6883f0ba-db83-519a-3f64-b048cc61590d.png)

で、下記のように、画面が表示されたら起動確認完了です。
![スクリーンショット 2022-06-17 0.50.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981122/f05d6547-62de-3aa6-d24b-a1d84885cf05.png)


デバッグできなくなったら、コンテナに入り、

```
docker exec -i -t echo-backend-v5-alpha_back_1 sh
```

`/go/src/app` パスで、

```
air -c ./air.toml
```

を実行してください。
![スクリーンショット 2022-06-17 1.01.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/981122/79f0fcf2-47d8-749d-9128-1dba3b42c874.png)
その後、再度、上記の手順通りに、デバッグ開始してください

しかし、何故、ホットローデイングとホットリロード + リモートデバッグの環境を分けているかというと、

ホットリロード + リモートデバッグは、go-delve + air
というライブラリーを使っており、この環境では、開発中にエラーが発生すると
コンパイルエラーが発生し完全にサーバー自体が止まってしまい為です。

ホットリロードは、freshというライブラリーを使っており、
こちらでは、コンパイルエラーが発生したとしても止まらず動いてくれる為
残しております。
go-delveとfreshを組み合わせて環境構築しようとしましたが、
うまくいかず断念しております。

fresh

https://github.com/gravityblast/fresh

go-delve + airの設定は下記を参考にさせて頂きました。

https://qiita.com/keitakn/items/f46347f871083356149b

---

動作確認

サインアップ
```
  curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"name":"Golang man", "email":"test@gmail.com", "password":"test5555"}' \
  localhost:5566/api/signup
```

レスポンス
```
  {"id":1,"name":"Golang man","email":"test@gmail.com","password":"$2a$10$/Yt3rqgEDNXf3Ot/Wf8qfempj/GJcGgv.f4cjioNvJXDR7kPgO2CS","created_at":"2022-06-15T15:30:03.1773644Z","updated_at":"2022-06-15T15:30:03.1773644Z"}
```

ログイン
```
curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"email":"test@gmail.com", "password":"test5555"}' \
localhost:5566/api/login
```

レスポンス
```
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiYWRtaW4iOnRydWUsImV4cCI6MTY1NTU2NjgyNn0.c1x7Eml70EkuvTT1DcfLlr9ECC7OuTUcQNDdbU74ot4"}
```

token認証確認
```
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiYWRtaW4iOnRydWUsImV4cCI6MTY1NTU2NjgyNn0.c1x7Eml70EkuvTT1DcfLlr9ECC7OuTUcQNDdbU74ot4" localhost:5566/api/auth/refresh
```
レスポンス
```
{"id":1,"name":"Golang man","email":"test@gmail.com","password":"$2a$10$/Yt3rqgEDNXf3Ot/Wf8qfempj/GJcGgv.f4cjioNvJXDR7kPgO2CS","created_at":"2022-06-16T00:30:03+09:00","updated_at":"2022-06-16T00:30:03+09:00"}
```


こちらリポジトリーになります。

反応が良ければこちらの記事やリポジトリー内容を更新しようと思いますので
記事が参考になりましたら、LGTMお願いします。

あと、別記事で、echoとNext.js(redux、redux-toolkit、react-hook)、ISR(incremental static regeneration)や
また、Nuxt.jsの3系が出たら、ISR(incremental static regeneration)も使えるので
backendとフロントを組み合わせたサンプル載せようと思っております。

https://github.com/usacoasts/echo-backend-v5-alpha