Go その2 Advent Calendar 2015 2日目です。
今日書くこと
- APIを提供するためのコード
- APIを利用するためのコード
- マイクロサービス (・∀・)ィィイイ!! かもしれない
- やれなかった / この記事には書いていないこと
以下サンプルで利用するコードは こちら。
お手元で起動する1 ための手順は READMEをご覧ください。
APIを提供するためのコード
Go言語には APIのためのよさげなフレームワークはありますが、
今回はそれらを使わずともかんたんに APIサーバが作れることをお伝えしたく。
ベースとなっている元ネタは A RESTful Micro-Framework in Go これなのですが
ここから、やりたいことができるように変えていった結果をサンプルに、
どうすれば APIサーバが書けるのかを記します。
-
まず、APIのエンドポイントが実装すべきインターフェイスを定義します
https://github.com/pottava/golang-microservices/blob/master/app-dbio/app/http/restapi.go#L32 -
すべて
StatusMethodNotAllowed
エラーとなるデフォルト実装をした構造を定義します
https://github.com/pottava/golang-microservices/blob/master/app-dbio/app/http/restapi.go#L51 -
各 APIエンドポイントは、2の構造を埋め込んだ構造を定義して
https://github.com/pottava/golang-microservices/blob/master/app-dbio/app/controllers/user.go#L18 -
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であれば返り値は JSON2 だと思うのですが、
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-compose3 を使い、ひとつのアプリケーションを
複数の小さなサービスで構成するのが趣味なのですが
ほんとにとてもいいのです。
- コンパイルがより高速: 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 でのエラーの再試行とエクスポネンシャルバックオフ
で、私はこれを このへん を参考に実装してみています。
テストが不十分なのでこれも今回のサンプルからは外しました。
Swaggger
いずれかをちゃんと使いたいと思いながら。アドカレに実例でるといいなあ
https://github.com/yvasiyarov/swagger
https://github.com/go-swagger/go-swagger