Go言語で REST API + マイクロサービス

[Go その2 Advent Calendar 2015](http://qiita.com/advent-calendar/2015/go2) 2日目です。

# 今日書くこと

* APIを提供するためのコード
* APIを利用するためのコード
* マイクロサービス (･∀･)ｨｨｲｲ!! かもしれない
* やれなかった / この記事には書いていないこと

以下サンプルで利用するコードは [こちら](https://github.com/pottava/golang-microservices)。
お手元で起動する[^1] ための手順は READMEをご覧ください。


# APIを提供するためのコード

Go言語には APIのためのよさげなフレームワークはありますが、
今回はそれらを使わずともかんたんに APIサーバが作れることをお伝えしたく。

ベースとなっている元ネタは [A RESTful Micro-Framework in Go](http://dougblack.io/words/a-restful-micro-framework-in-go.html) これなのですが
ここから、やりたいことができるように変えていった結果をサンプルに、
どうすれば APIサーバが書けるのかを記します。
　  

1. まず、APIのエンドポイントが実装すべきインターフェイスを定義します
https://github.com/pottava/golang-microservices/blob/master/app-dbio/app/http/restapi.go#L32

2. すべて `StatusMethodNotAllowed` エラーとなるデフォルト実装をした構造を定義します
https://github.com/pottava/golang-microservices/blob/master/app-dbio/app/http/restapi.go#L51

3. 各 APIエンドポイントは、2の構造を埋め込んだ構造を定義して
https://github.com/pottava/golang-microservices/blob/master/app-dbio/app/controllers/user.go#L18

4. API実装したい HTTPメソッドだけ、ロジックを書きます
https://github.com/pottava/golang-microservices/blob/master/app-dbio/app/controllers/user.go#L22

かんたんですね！

RESTful風 APIにしたければ、こんな感じでリソース IDをベースに分岐することもできますし
https://github.com/pottava/golang-microservices/blob/master/app-dbio/app/controllers/user.go#L24
POSTや PUTのように、bodyから JSONを取り出したければこんな感じで実装できます。
https://github.com/pottava/golang-microservices/blob/master/app-dbio/app/controllers/user.go#L41
サンプルにはないですが、クエリ文字列から引数を受け取りたければ
`queries.Get("limit")` などと書けます。


メソッド名が変だとか、そもそも APIサーバなんだから
パッケージ名は `controllers` じゃなくて `resources` だろ
といった暖かいメッセージは受け付けていません。赦してください。


# APIを利用するためのコード

RESTな APIであれば返り値は JSON[^2] だと思うのですが、
https://github.com/pottava/golang-microservices/blob/master/app-webui/app/models/api.go#L40
引数 `resJSON` に構造体のポインタを渡してあげます。
JSONではなく文字列がよければ `nil` を渡し、関数の返り値として受け取れます。

例えばデータ取得 APIからユーザ情報を受け取るときはこんな感じです。
https://github.com/pottava/golang-microservices/blob/master/app-webui/app/models/user.go#L29

ちなみに細かいことですが、サーバサイドが対応しているなら
圧縮解凍ロジックがあっていいのではと思う私です。
https://github.com/pottava/golang-microservices/blob/master/app-webui/app/models/api.go#L43

余談ですが、このサンプルでは API結果に「エンベロープ」がありますが
なければもっとシンプルでいいのかもしれません。
このへんは完全に好みですね！


# マイクロサービス (･∀･)ｨｨｲｲ!! かもしれない

docker-compose[^3] を使い、ひとつのアプリケーションを
複数の小さなサービスで構成するのが趣味なのですが
ほんとにとてもいいのです。

* コンパイルがより高速: Goとはいえ、モノリシックにつくるとコンパイルに数秒かかるように..
* APIを RESTfulにしやすい: セッションの分離 & サーバ間のみにアクセス制限するのがかんたん
* 一部サービスの更新、引き継ぎ、モック化、エンドポイント変更、開発言語の変更などが容易
* サービスが依存する引数・環境変数が明確になって管理がらくになる

などなど..

ちなみに、今回ユーザ認証も単独のサービスにした影響で
CORSと Ajaxの設定にあまり使わないものをセットしたので書き残します。

https://github.com/pottava/golang-microservices/blob/master/app-authentication/app/http/http.go#L133
https://github.com/pottava/golang-microservices/blob/master/app-webui/app/assets/js/app/index.jsx#L7

両方書かないと Cookie渡せないんですね！（小並感）


# やれなかった / この記事には書いていないこと

## スロットリング

API提供側にはスロットリングがあるといいかと思います。
実際にちゃんとコードを書いたら設定値周辺が複雑になってしまったので
今回の例からは全部省きましたが、私はこれ使ってます。
http://gopkg.in/throttled/throttled.v2

## Exponential Backoff

API利用側のお話ですが、エラー時のリトライアルゴリズムです。
指数関数的後退と訳されたりもしますがこれ大事。
以下 AWSの記事ですが、知らない方はぜひ。
[AWS でのエラーの再試行とエクスポネンシャルバックオフ](https://docs.aws.amazon.com/ja_jp/general/latest/gr/api-retries.html)

で、私はこれを [このへん](https://github.com/aws/aws-sdk-go/blob/master/aws/request/retryer.go) を参考に実装してみています。
テストが不十分なのでこれも今回のサンプルからは外しました。

## Swaggger

いずれかをちゃんと使いたいと思いながら。アドカレに実例でるといいなあ
https://github.com/yvasiyarov/swagger
https://github.com/go-swagger/go-swagger
　

[^1]: dockerの新しいネットワーク機能を使うため、docker-composeは v1.5以降が必要です
[^2]: XMLのケースは書いたことないですすみません
[^3]: docker-composeなしでマイクロサービスを作るのはつらすぎだと思う