久しぶりにGoでAPIサーバーを書いてみる

## 概要

- Go1.11からの新しい依存解決システムvgoはよい
- 昔はGoでMongoDBを使うときはmgoを使っていたが、Go1.10+ならMongoDBの提供するmongo-go-driverが使える
- freshを使えばGo製サーバーもライブリローディングしながら開発できる
- 自分と同じようにGoを敬遠していた人もそろそろ始めどきかも

## はじめに

久しぶりにGoを使ってJSON APIサーバーを書く機会がありました。

Goは1.6とかの時代にちょっと触っていたのですが[^1]、Python, Ruby, Nodeといったスクリプト系言語を主な使用言語としている自分にはだるいな…と思うことが多々ありましたし、ディレクトリの場所が規定されてしまうというのも嫌だなぁと感じていました。
というわけでしばらくGoとはサヨウナラをしていました。

しかし最近バックエンドでGoを本格利用している会社の方が、最近Goもいろいろ変わっていてそろそろ再チャレンジするにはいい機会ですよ！と教えてもらいました。
特にGo1.11ではvgoという新しいバージョン管理システムが試験的に導入されており、これを使えばGOPATHはもういらないとのこと。

スキルセットとして低レイヤーなことができてWASM時代にも備えられる言語に触れておきたい、でも言語仕様が難しいやつはちょっと…という自分にとってGoはまさしく求めているものだという自覚はありました。
ちょうどプロトタイプを一個作ってみるといった案件があったため、これは何かの機会だと思い再びGoにチャレンジしてみました。

## Docker

Goのバージョンを持っているPC全部でそろえるのは面倒なのでDockerを使うことに。
これだと別にvgo関係なくGOPATHどうこう気にする必要はなかったですね、、。

### Dockerfile

```Dockerfile
FROM golang:1.11
WORKDIR /go/src/app

RUN go get github.com/pilu/fresh
ENV GO111MODULE=on
CMD ["fresh"]
```

`ENV GO111MODULE=on`によってvgoが使えるようになりますが、その後 `go get` がうまく動かなくなるので先に `go get` しています。
vgoが有効だと、相対パス記法でのインポートなど古い仕様を切り捨てるようになっているようでその影響かなぁと。

### docker-compose.yaml

```yaml
version: '3'
services:
  app:
    build:
      context: ./app/docker
    ports:
      - 8081:8081
    volumes:
      - ./app/src:/go/src/app
    command: fresh
```

開発ディレクトリ(`./app/src`)をDockerfileで指定した作業ディレクトリにマウントします。これで`fresh`を実行すると、自動的に`main.go`が立ち上がるようです。freshについては後述。

まだビルドしてバイナリを出力するところまでは必要としていないので、まだその対応はしていません。

## vgo

新しい依存管理システムです。importを書いておけば明示的にinstallとかしなくても必要があれば勝手にダウンロードしてくれる、Rubyのbundlerやnodeのnpmのようにバージョンロックできるというのが特徴です。

これを有効にすると相対パスを使ったインポートが使えなくなります。

:no_good: 

```go:main.go
import (
    "./lib",
)
...
```

`main.go`と同じディレクトリに`go.mod`を作成し、そこでプロジェクト名を定義し、`<プロジェクト名>/<パス>`というようにインポートします。

:ok_woman: 

```:go.mod
module app
```

```go:main.go
import (
    "app/lib"
)
...
```

参考
[go 1.11のmodules(vgo)が有効な環境で相対importが cannot find module for path でエラーになった話。](https://pod.hatenablog.com/entry/2018/12/26/074944)

## mongo-go-driver

GoでMongoDBを使う際は、[mgo](https://github.com/go-mgo/mgo)というライブラリを使うのが定番だったようです。しかしこれはメンテナンス停止が宣言されており、[フォーク](https://github.com/globalsign/mgo)されたものを使っているケースが多いみたいですね。

しかし、MongoDBから[mongo-go-driver](https://github.com/mongodb/mongo-go-driver)というのがリリースされています。昨年12月にようやくアルファからベータになったばかりです。
Go1.10以上ということなので、これからGo+MongoDBという構成を導入するプロジェクトはこれを使ってみてもよさそうです。

## fresh

[fresh](https://github.com/gravityblast/fresh)というツールを使えば、Railsで開発しているのと同じようにライブリローディングが使えます。同じようなことを実現するツールには[gin](https://github.com/codegangsta/gin)というものもあります。(Webフレームワークの[gin](https://github.com/gin-gonic/gin)とは別物)

どちらもあまり更新されていないようです…。が、あるのとないのとだと開発中の気持ちよさが全然違います。
Goをだるいと感じていた最大の原因がコードを変えたらプロセスを立ち上げ直す必要がある、だったのでそれがなくなると気分的にはRailsで開発しているのとそう変わりません。

ちなみに、freshを使った環境構築はこちらを参考にしました。
[Go v1.11 + Docker + fresh でホットリロード開発環境を作って愉快なGo言語生活](https://qiita.com/po3rin/items/9acd41ef428436335c97)

私はginではなく昔触ったことのある[echo](https://github.com/labstack/echo)を使っていますが、全く同じ方法でOKです。

----

GOPATH云々はDockerを使えばもともと気にする必要がなかったわけですが :sweat_smile: 
vgoはGoの依存解決の決定版になるのでしょうか。まだ軽く触っている段階ですが、だいぶ体験としてはよいですね。`bundle install`とか`npm install`とか、よくよく考えたら明示的に呼び出す必然性ってないですね。
(昔depというのがあったように思うのですが、同じようにまた新しいのが出てきたりしないでほしいなー…と思います。)

自分と同じように、昔触ったことがあるけどちょっとめんどくさくなって…という方は、そろそろ再チャレンジしてみてもよいかもしれません。

[^1]: そのころGoで「世界で闘うプログラミング力を鍛える150問」を解いていたときの残骸です。https://github.com/k5trismegistus/cracking-the-coding-interview-150