View のバグで REpresentational State Transer が使いにくい件/使いやすくするには...

RESTのクライアントが効率的な1次元の順序付き(前,次が定義された)集合を走査するためには(例えばPagination)、、、、

a) GET したリソースのサブセットが何件あって、b) スーパーセットは何件あって、c) サブセットはどこにいるのか(1次元の集合であれば先頭からのオフセット)の情報をクライアントに返すことが非常に重要だ、というプラクティスを身をもって体験中。結論から言うと、RESTで集合を返すリソースは d) ほかのサブセットを取得するためのURIの情報を返さないと使いづらすぎるよ!という話で、ハイパーリンクの本質?がやっと分かってきた気がする?

以下ぐだぐだ考えを整理。使いやすくするには... のところは、自宅のルーターが落ちているような気がするので(HTTPコネクションがはれない, 実家に帰省中)、自宅に戻ってからソースをサブミットしてからということで。

続きは読んでもしょうがない、単なるメモ。


1. d) ハイパーリンクがある場合

例えば、1次元順序集合 A={a,b,c,d,..,z, aa, ab, ... } があったとして、最初のリクエストで集合の中から3つ頂戴といって、 {a,b,c} を取ったとする。クライアントは「前へ」、「次へ」などでリンクを辿るであろう。ここで、前、および次が、(null, 4) とそれぞれ、ハイパーリンクで表されていれば、クライアントはAに対して「前へ」を選ぶときは、「null から 前に向かって、3つ頂戴」というリクエストをとばし、404が返ってくれば、ああー、nullは「ない」を意味するのか、と分かる。もちろん、Common Sense で null はもうないんだな、と思ってもよい。「次へ」を選ぶときは、「4 から次に向かって、3つ頂戴」ということで、{4,5,6} が取得できて (前,次) は (3, 7) となる。どんどんいけば、そのうち、(xxx, null) に なるだろう。無限集合だったらならないけど、それはサーバーとクライアントの根比べってことで。

このようにハイパーリンク相当のものをサーバーが返してくれると、集合をくまなく走査する場合にクライアントは非常にうれしい。

偶数だけとりたい? それは A を全部取って、偶数だけ取り出して、それを新しい集合 B(つまりURI)としてサーバーに保存すればいいんだ。もちろん、サーバーが親切な設計であれば、偶数だけを取り出すためのリクエストパラメーターを用意してくれているかもしれない。

2. a) - c) のセットでクライアント側で d) を計算する

先ほどの、1次元順序集合 A={a,b,c,d,..,z, aa, ab, ... } があったとして、最初のリクエストで {a,b,c} を取ったとする。このとき、(全部で, 今ここ) をサーバーが(N, 0番目) として教えてくれる。1次元順序付き、ということで、0番目の前はあるわけがない。まぁ、-1番目から前に向かって3つ頂戴! といっても、404でOK。

さて、(N, 0番目) と ({a,b,c}.length=3つ)という情報から、次は 0 + 3 = 3番目 ということが計算できますから、3番目から3つくれ、といえば {d,e,f} (N, 3番目) がもらえるのでしょう。ハイパーリンクを直接提供しない場合は、ハイパーリンク代わりに与えた情報(この場合0番目、という情報)と同じ種類の情報(3番目)クライアントからリクエストされるので、サーバーはそれに応答できる必要がある、と。

で、(N,3番目) と ({d,e,f}.length=3つ)という情報から、次は 3 + 3 = 6番目 ということが計算できる。この辺は最初と同じで、前を辿る場合に関しては、3 - 1 = 2番目から前3つ、という形になる。

3. a) - b) のセットでクライアント側で d) を計算する( c) の情報がない場合 )

先ほどの、1次元順序集合 A={a,b,c,d,..,z, aa, ab, ... } があったとして、最初のリクエストで {a,b,c} を取ったとする。このとき、(全部で) をサーバーが(N) として教えてくれる。{1,2,3}.length < N であれば、「ほかにもリソースはあるはず」ということで、次か前のリクエストを試みるが、{1,2,3} が順序集合のどこに位置するかは分からないため、「{1,2,3}の次を頂戴」とか「{1,2,3}の前を頂戴」とかいう形で、サブセットそのものを送りつけて、サーバー側に、次、前を解釈してもらうことになる。これは、集合の要素のサイズが大きかったりする場合は、非常に効率的でない。

1-3 のケースをみると分かるように、次、前、を辿るための情報を何らかの形で返しているが、結局、ハイパーリンクが一番落ち着く形である。

CouchDB のViewの実装では、2 の実装になっていて、しかも、XXXXX なので非常に使いづらいのである、という主張をしたいのだけれど。面倒になってきたので。(というかCouchDBバインディングを作っていて、クライアント側でごり押しして解決したのでどうでもよくなった & CouchDB のMLあさってたら、「もう少しPagination使いやすくしようよ!」という話が起こっていたので。ヒントはハイパーリンクだと思う。というか全般的に、CouchDBハイパーリンクの仕組みをつけるべきだと思う。それだとXMLと変わらないかなぁ、、でも妥協点として、_link : { _next : ".....", _prev : ".....", user_link : "...." } 的なものがあっても*1

*1:ここでErlangで feature パッチを作ってやるといいのだろうけど、残念ながら、Erlang のスキルが足りないorz