go言語のgoaでAPIをつくる


go言語のgoaというフレームワークを使ってAPIをつくってみます。
https://goa.design/

go初心者なのですが、習うより慣れろがモットーなので、
まずは、さくっといろいろお触りできる環境をつくりました。
手順のメモです。
（環境は、壊したり汚したりしても良いように、docker上につくりました）

- centos7
- go1.9
- goa v1.3.0
- glide v0.12.3 (パッケージ管理)
 

## dockerコンテナを準備する
（dockerのインストール手順や扱い方は割愛します）

- centos7の、docker image を取得する

```
docker pull centos:7
```

- dockerコンテナを起動する

```
mkdir -p ~/Src/centos7-go
docker run --privileged -it -d -v ~/Src/centos7-go:/go -h go -p 8000:80 --name centos7-go centos:7 /sbin/init
```

　　`-v` オプション: 
　　　IDE大好き派なので、ローカルで作業できるよう共有ディレクトリを設定してます。
　　　ローカル環境の作業ディレクトリは、`~/Src/centos7-go` としました。
　　`-p`
　　　それなりに動くものができたら、nginxとかで動かしたいために設定してます。
　　　（本エントリーでは扱いません）


- dockerコンテナに接続する

```
docker exec -it centos7-go bash
```

- centosの初期設定をば最低限
 
（地味に時間がかかるので、Dockerfile化 & build した。割愛。）

```
yum -y update
yum install -y git wget
```

## goをインストールする


- ダウンロードURLを本家サイトで調べる

https://golang.org/dl/

![Kobito.egUJ1M.png](https://qiita-image-store.s3.amazonaws.com/0/116449/38156525-b46b-f35c-4b06-e890d045228f.png "Kobito.egUJ1M.png")


- ダウンロードして展開する

```
cd /usr/local/src
wget https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz
tar -C /usr/local/ -xzf go1.9.linux-amd64.tar.gz
```


- PATHを指定する

```
vi ~/.bashrc
```

```
export GOROOT=/usr/local/go
export GOPATH=/go
export PATH=$PATH:$GOROOT/bin
export PATH=$PATH:$GOPATH/bin
```

```
source ~/.bashrc
```

　`$GOPATH`(=ローカルPCとの共有ディレクトリに設定)
　ここの配下にプログラムをガシガシつくっていくことになります。

- インストールできてるか確認する

```
go version
```

- `$GOPATH` に指定したディレクトリを作成しておく

　必要な場面で「そんなディレクトリないっす」って怒られたので。

```
mkdir -p $GOPATH/bin
```


## glideをインストールする

rubyにおけるGemfile、PHPにおけるcomposer的なものは存在しないのだろうか？と、
ググってみたらgoにもいろいろありました。
glideが最強との説が多かったので導入します。

- インストール

```
curl https://glide.sh/get | sh
```

- 確認

`$GOPAH/bin` の下にインストールされました。

```
/go
|-- bin
|   `-- glide
`-- src
```

## goaをインストールする

goaのドキュメントを参考にしました。
https://goa.design/design/vendoring/


- アプリ用のディレクトリを作成する

ソースコードは `$GOPATH/src` ここの下に配置していくのだそうです。
このあとAPI作成で参考にするチュートリアルのために、`cellar` というプロジェクトをつくっていきます。

```
mkdir -p $GOPATH/src/cellar && cd $GOPATH/src/cellar
```

- glide 初期化

```
glide init
```

- 確認

`glide init` コマンドにより、glide.yaml というファイルがつくられます。

```
/go
|-- bin
|   `-- glide
`-- src
    `-- cellar
        `-- glide.yaml
```

- glide.yamlを編集する

```
package: cellar
import:
- package: github.com/goadesign/goa
  version: master
  vcs: git
  subpackages:
  - client
  - design
  - design/apidsl
  - dslengine
  - goagen
  - middleware
- package: golang.org/x/tools
  subpackages:
  - go/ast/astutil
- package: gopkg.in/yaml.v2
```

- パッケージをインストールする

`glide.yaml` に記載のとおりにパッケージがインストールされます。

```
glide install -v
```

- 確認

    - `vendor` ディレクトリ以下に、パッケージがインストールされている
    - `glide.lock` ファイルが作成されている
        - バージョン、ブランチなどの指定は、`glide.yaml` にちゃんと書けば可能。安心。
        - Github Enterprise 管理とかの独自パッケージもインストールできます。

```
/go
|-- bin
|   `-- glide
`-- src
    `-- cellar
        |-- glide.lock
        |-- glide.yaml
        `-- vendor
            |-- github.com
            |   |-- armon
            |   |-- dimfeld
            |   |-- goadesign
            |   |-- manveru
            |   |-- satori
            |   |-- spf13
            |   `-- zach-klippenstein
            |-- golang.org
            |   `-- x
            `-- gopkg.in
                `-- yaml.v2
```

- goagenをビルドする

実行ファイルが存在しないので、ビルドしてあげます。

```
cd ./vendor/github.com/goadesign/goa/goagen
go build
cd ../../../../../
```

※ パッケージが足りません、というエラーが出ると思います。
本エントリの下の方に対応方法を記載しています。

## APIデザインを作成して、とりあえず動かしてみる

以降は、以下のサイトを参考に進めます。
https://goa.design/ja/learn/guide/


- 参考サイトに記載のとおり `design.go` を作成する

まるっとコピペでOK。

```
mkdir -p $GOPATH/src/cellar/design
vi $GOPATH/src/cellar/design/design.go
```

- 定形コードを生成する

`desin.go` の内容を元に、定形のディレクトリ構成、必要なファイルが生成されます。
でざいんふぁーすと！

```
cd $GOPATH/src/cellar
./vendor/github.com/goadesign/goa/goagen/goagen bootstrap -d cellar/design
```

- `bottle.go` を編集する

参考サイトのとおりに編集します。(「`Show` メソッドを置き換えて」の部分)
import に "fmt" を追加する、という旨の説明が抜けているので、追記する。

```
vi $GOPATH/src/cellar/bottle.go
```

- ここまでやると、APIとりあえず動く！ 実行してみる

```
go run *.go
```

- 動作確認

```
curl -i localhost:8080/bottles/1
```

以下のような結果が帰ってきました。YATTA〜！

```
[root@go cellar]# curl -i localhost:8080/bottles/1
HTTP/1.1 200 OK
Content-Type: application/vnd.goa.example.bottle+json
Date: Tue, 05 Sep 2017 05:57:31 GMT
Content-Length: 48

{"href":"/bottles/1","id":1,"name":"Bottle #1"}
```

ここから、いろいろ肉付けしていきます。

今回はここまで。
おわりです。

---

## appendix

- パッケージが足りないよのエラー対応

以下のようなエラーが出たら、`glide.yaml` にパッケージを追記します。

```
../design/definitions.go:11:2: cannot find package "github.com/dimfeld/httppath" in any of:
	/go/src/cellar/vendor/github.com/dimfeld/httppath (vendor tree)
	/usr/local/go/src/github.com/dimfeld/httppath (from $GOROOT)
	/go/src/github.com/dimfeld/httppath (from $GOPATH)
```

今回は、最終的にこうなりました。

```glide.yaml
package: cellar
import:
- package: github.com/goadesign/goa
  version: master
  vcs: git
  subpackages:


  - client
  - design
  - design/apidsl
  - dslengine
  - goagen
  - middleware
- package: golang.org/x/tools
  subpackages:
  - go/ast/astutil
- package: gopkg.in/yaml.v2
- package: github.com/dimfeld/httppath
- package: github.com/manveru/faker
- package: github.com/satori/go.uuid
- package: github.com/spf13/cobra
- package: github.com/spf13/pflag
- package: github.com/zach-klippenstein/goregen
- package: github.com/armon/go-metrics
- package: github.com/dimfeld/httptreemux
- package: golang.org/x/net/websocket
```

以下のコマンドで、パッケージの追加インストールを行います。

```
cd $GOPATH/src/cellar
glide up
```

## 感想

未経験なのに突然、RoRやCakePHPのチュートリアルからはじめて、
「ruby, PHP できます！」　などと、宣言したくなってしまう心理が
ほんのちょっぴりだけ、分かったような、分からないような...

実は今回、goをちゃんと学ぶ前に、いきなりgoaの情報から漁るという暴挙に及んでしまったのです。
そのため、いらぬ試行錯誤や失敗が...orz 反省。
間違いや、他の良法などありましたら、コメントいただけますと幸いです。