HTTPをMessagePack-RPCに変換する方法

HTTPは、クライアントは楽だけどサーバは大変。完全でセキュアで堅牢なHTTPのサーバに書くのは異常に難しい。
MessagePack-RPCは、クライアントで使えないかもしれないけど、サーバは書きやすい。それからRPCの弊害として、クライアントとサーバが簡単に密結合化してしまう。
サーバもクライアントも楽したい => HTTPをMessagePack-RPCに変換すればいい。

案1:URLに埋め込む

ぱっと思いついた方法。
"/method?param1=value1¶m2=value" のように、URLにRPCのメソッド名と引数を埋め込む。返り値はJSONに変換して返す。

利点

クライアントはお気楽。

欠点

RPCではメソッドの引数は配列だが、この案では連想配列なので、どうにかする必要がある。
引数に型がない。
返り値はどうしよう。


案2:JSON-RPC over HTTP

クライアントはJSON-RPC over HTTPを実装する
リクエストは全部POSTで、URLはRPCサーバの位置を表し、bodyにJSONを埋め込む。JSONの形式はJSON-RPCに従う。
http://json-rpc.org/wiki/specification

利点

引数に型がある。
JSON-RPCにはシーケンスIDを埋め込む仕様があるので、クライアントでとってもがんばれば、非同期RPCが可能。
どんなメソッドでも呼べる。
どんなエラーでも返せる。

欠点

いつでもJSONを作ってPOSTしないといけない。ちょっとしたことはGETでやりたい。
クライアントはJSON-RPCの仕様に従って、要求を作ったり返り値を取り出したりする必要がある。クライアント側にも一枚ラッパがないと使いにくい。ふつうのHTTPクライアントで直接使えないと旨味減。


案3:REST

GETは、"/path?param1=value"のように、URLの中にパスとパラメータを埋め込み、GET("path", params)というRPC呼び出しに変換する。返り値はJSONに変換して返す。エラーはHTTPのコードで返す。
POSTは、URLを第一引数、bodyをJSONとして、POST("path", params)というRPC呼び出しに変換する。返り値はJSONに変換して返す。エラーはHTTPのコードで返す。
PUTは、URLを第一引数、bodyを第二引数として、PUT("path", body)というRPC呼び出しに変換する。エラーはHTTPのコードで返す。
DELETEは、URLを第一引数として、DELETE("path")というRPC呼び出しに変換する。エラーはHTTPのコードで返す。

利点

GET,POST,PUT,DELETE以外のメソッドを呼べないので、疎結合化を強制できる。
リソース(パス)に対する操作(GET/POST/PUT/DELETE)という概念。

欠点

GET,POST,PUT,DELETE以外のメソッドを呼べない。
サーバ側の実装で、リソースに対する操作という概念に合わないと困る。
GETとPOSTの返り値で、trueとか1はJSONとして認められていなかった気がする。連想配列以外を返しても良いのか微妙。


案4:Webアプリケーションフレームワーク

POSTと、なんとなくGETでは、URLはリソースではなくサーバーのコマンドを示すそうだ。
GETは、"/method/arg1/arg2?param1=value"のように、URLの中にメソッドと引数とパラメータを埋め込み、method("arg1", "arg2", params)というRPC呼び出しに変換する。返り値とエラーはRESTと同じ。
POSTは、"/method/arg1/arg2"のように、URLの中にメソッドと引数を埋め込み、bodyをJSONとして、method("arg1", "arg2", params)というRPC呼び出しに変換する。返り値とエラーはRESTと同じ。
PUTは、RESTと同じだが、どうせ使わないんじゃないか。
DELETEは、RESTと同じだが、きっと使わないだろう。

利点

よくあるWebアプリケーションのように見える。

欠点

GETとPOSTで、引数に型がない。文字列しか渡せない。
GETで、パラメータに型がない。ただし、POSTを使えば済む。
サーバ側でラッパを書くなりしないと、クライアントとサーバが密結合化してしまう。文字列と連想配列しか渡せないのはちょうど良いかも。
GETとPOSTの返り値で、trueとか1はJSONとして認められていなかった気がする。連想配列以外を返しても良いのか微妙。


所感

HTTPを使ってサーバにアクセスしたいケースというのは、クライアントとサーバは別のサービスになっていて、疎結合化したいケースだろう。何も考えずに組むと密結合になりがちなので、最初から密結合にしかならない方法は優れている。
というわけで、どうがんばっても疎結合にしかできないRESTは良さそう。ただサーバ側の実装は大変。
うまい妥協案として、Webアプリケーションフレームワーク風は良さそう。