JSON-RPC, RESTful API とクエリパラメータ
OpenSocial の JSON-RPC, RESTful API の設計についてのよもやま話です。
JSON-RPC とクエリパラメータ
OpenSocial Core API Server Specification 1.1 に URL Addression と言うセクションがあります。
これは JSON-RPC を http GET で呼び出す際に params の部分など構造化されたデータをどうやって渡すのって際の仕様になります。
JSON Object | URL Parameter | ||
{ "field" : "value" } | field=value | ||
{ "field" : [1,2,3,4,5]} | field=1,2,3,4,5 | ||
{ "field" : "12" } | field='12' | ||
{ "field" : [identifier,anotheridentifier]} | field=identifier,anotheridentifier | ||
{ "field" : ["value","another value"]} | field=value,"another value" | ||
{ "field" : ['value','another value']} | field=value,'another value' | ||
{ "field" : { "nested" : "value" }} | field.nested=value | ||
{ "field" : [{ "nested1" : "value1" }, { "nested2" : "value2" }]} | field(0).nested1=value1&field(1).nested2=value2 |
まぁシングルクオートとダブルクオートを意図的に使い分けたいユースケースがさっぱり意味が分からない上に、identifier とか意味分かんないんでこの辺り謎過ぎるのですが、そういう細かい突っ込みはとりあえず置いておきます。
ところで JSON-RPC 2.0 の extension として定義されている JSON-RPC over HTTP によれば、GET の時の挙動は3.5 GET に書いてあり、params の部分はエンコードしろと書いてあります。どういう風にエンコードするかと言えば Base64 して URL Encode しろと言う感じです。
Pre-Encoded Params: http://<end point>?method=sum¶ms={"a":3,"b":4}&id=2 http://<end point>?method=sum¶ms=[3,4]&id=1 Encoded Request: http://<end point>?method=sum¶ms=eyJhIjozLCJiIjo0fQ%3D%3D&id=2 http://<end point>?method=sum¶ms=WzMsNF0%3D&id=1
って感じ。これはこれで単純明快ですね。
ちなみに先に JSON-RPC に対して結論を言っておくと、誰が楽しくて GET で叩くのか僕には意味が分かりません!*1大人しく POST 使いましょう。
RESTful API とクエリパラメータ
それでもやっぱり RESTful API が好き!と言う方も多いでしょう。僕もそうです。何度痛い目に合っても何故か好き。
まぁそんなことはどうでも良いのですが、OpenSocial RESTful API は中々面白い機能が幾つかあって、
- Partial Update
- Filter & Sort
辺りが挙げられます。Partial Update は冷静に考えると利便性の観点から出来て然るべきなんですが、ここでは触れない事にします。
Filter & Sort の辺りは Open Search 辺りからやってきた概念でしょう。
Filter や Sort なんですけど、例えばこんな風に書きます。
http://example.com/people/@me/@friends?filterBy=displayName&filterOp=startsWith&filterValue=zigo&sortBy=id&sortOrder=descending&count=50&startIndex=1
まぁ特に説明しなくても理解出来るとは思いますけど。
現時点の RESTful API の仕様では filter をもっと複雑に記述するなんて事は出来ません。と言うのも AND なのか OR なのかを指定する仕組みが無いからだと思うのですが、まぁ OR は要らないすよね。
そこで冒頭の JSON-RPC の URL Addressing から Syntax を借りてくると、こんな風に書けるかもしれません。
http://example.com/people/@me/@friends?filterBy(0)=displayName&filterOp(0)=startsWith&filterValue(0)=zigo,kaz,hid&filterBy(1)=gender&filterOp(1)=equals&filterValue(1)=male
この部分をデータ構造にすると、
{ "filterBy": ["displayName", "gender"], "filterOp": ["startsWith", "equals"], "filterValue": [ ["zigo", "kaz", "hid"], "male" ] }
みたいな感じとなり、SQL で表現すれば、
WHERE ( displayName LIKE 'zigo%' OR displayName LIKE 'kaz%' OR displayName LIKE 'hid%' ) AND gender = 'male';
のようになると。
実は某プラットフォームの API v2 ではこの記法が使えるらしいのですが、とりあえず undocument & no supports です。
雑感
とりあえず JSON-RPC に関して仮に GET をサポートするのであれば本家の方の仕様( Base64 )の方がすっきりしていて良いかなと思います。あと、一般論としてクエリパラメータとして何か構造化されたデータを埋め込む場合も、これと同様の手法の方が便利だろうなと思います。
RESTful API と filter の議論ですけど、こういうのもありかなとは思います。
*1:監視用途とかなら意味があるかもしれない