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


Go その2 Advent Calendar 2015 2日目です。

今日書くこと

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

以下サンプルで利用するコードは こちら
お手元で起動する1 ための手順は READMEをご覧ください。

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

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

ベースとなっている元ネタは A RESTful Micro-Framework in Go これなのですが
ここから、やりたいことができるように変えていった結果をサンプルに、
どうすれば 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であれば返り値は 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
 


  1. dockerの新しいネットワーク機能を使うため、docker-composeは v1.5以降が必要です 

  2. XMLのケースは書いたことないですすみません 

  3. docker-composeなしでマイクロサービスを作るのはつらすぎだと思う