Posted at

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

More than 3 years have passed since last update.

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なしでマイクロサービスを作るのはつらすぎだと思う