私はJSONドキュメントのコレクションに直接RESTインターフェースを公開することに興味があります(カウチDBまたは忍耐する)。私が直面している問題は、GET
コレクションが大きい場合にコレクション ルートでの操作をどのように処理するかということです。
例として、Questions
各行がドキュメントとして公開される StackOverflow のテーブルを公開しているとします (必ずしもそのようなテーブルがあるわけではなく、大量の「ドキュメント」コレクションの具体的な例にすぎません)。コレクションは、/db/questions
通常の CRUD API を使用してで利用可能になりますGET /db/questions/XXX
。が使用されています。コレクション全体を取得する標準的な方法は ですがPUT /db/questions/XXX
、これが単純に各行を JSON オブジェクトとしてダンプすると、かなり大きなダウンロードが発生し、サーバー側で多くの作業が発生します。POST /db/questions
GET /db/questions
解決策はもちろんページングです。Dojoはこの問題をJsonRestストアRange
ヘッダーをカスタム範囲単位とともに使用するという、RFC2616 準拠の巧妙な拡張を介して行われますitems
。その結果、206 Partial Content
要求された範囲のみを返す が生成されます。クエリ パラメータに対するこのアプローチの利点は、クエリ文字列がクエリ (たとえば、GET /db/questions/?score>200
または など、エンコードされます%3E
) に残されることです。
このアプローチは私が望む動作を完全にカバーしています。問題はRFC 2616206 応答で次のように指定します (強調は筆者による):
のリクエストRangeヘッダーフィールド(セクション14.35) は、希望する範囲を示し、If-Range ヘッダーフィールド (セクション14.27) を使用して、リクエストに条件を付けます。
これは、ヘッダーの標準的な使用法のコンテキストでは意味をなしますが、単純なクライアントやランダムに探索する人々を処理するために 206 応答をデフォルトにしたいので、問題があります。
私は解決策を探して RFC を詳細に調べましたが、自分の解決策に満足できず、SO がこの問題についてどう考えているのか興味があります。
私が考えたアイデア:
200
ヘッダーで返すContent-Range
!- これは間違っているとは思いませんが、応答が部分的なコンテンツのみであることを示すより明確なインジケーターがあればよいと思います。- 戻る
400 Range Required
- 必須ヘッダーには特別な 400 応答コードがないため、デフォルトのエラーを使用して手動で読み取る必要があります。これにより、Web ブラウザー (または Resty などの他のクライアント) を介した調査も困難になります。 - クエリパラメータを使用する- 標準的なアプローチですが、Persevere のようなクエリを許可したいと考えており、これによりクエリ名前空間が削減されます。
- ただ戻るだけ
206
!- ほとんどのクライアントはパニックに陥らないと思いますが、RFCのMUSTに反対するのは避けたいです - スペックを拡張!戻る
266 Partial Content
- 206 とまったく同じように動作しますが、ヘッダーを含んではならないリクエストに応答しますRange
。266 は衝突の問題に遭遇しないほど十分に高い値であると考えており、納得できますが、これがタブーと見なされるかどうかはわかりません。
これはかなり一般的な問題だと思いますので、私や他の誰かが車輪の再発明をしないように、これが事実上のやり方で行われることを望みます。
コレクションが大きい場合、HTTP 経由で完全なコレクションを公開する最適な方法は何ですか?
ベストアンサー1
皆さんの中には、あまり賛成できない人もいます。私は数週間、REST サービス用のこの機能に取り組んできました。最終的に行ったことは非常に単純なものでした。私のソリューションは、REST の人々がコレクションと呼ぶものにのみ意味をなします。
クライアントは、コレクションのどの部分が必要かを示すために「Range」ヘッダーを含める必要があります。または、要求されたコレクションが大きすぎて 1 回のラウンドトリップで取得できない場合に 413 REQUESTED ENTITY TOO LARGE エラーを処理できるように準備する必要があります。
サーバーは、リソースのどの部分が送信されたかを指定する Content-Range ヘッダーと、コレクションの現在のバージョンを識別する ETag ヘッダーを含む 206 PARTIAL CONTENT 応答を送信します。私は通常、Facebook のような ETag {last_modification_timestamp}-{resource_id} を使用し、コレクションの ETag は、コレクションに含まれる最も最近変更されたリソースの ETag であると考えています。
コレクションの特定の部分を要求するには、クライアントは「Range」ヘッダーを使用し、「If-Match」ヘッダーに、同じコレクションの他の部分を取得するために以前に実行された要求から取得したコレクションの ETag を入力する必要があります。これにより、サーバーは、要求された部分を送信する前に、コレクションが変更されていないことを確認できます。より新しいバージョンが存在する場合は、412 PRECONDITION FAILED 応答が返され、クライアントにコレクションを最初から取得するように促します。これは、現在要求されている部分の前または後に、一部のリソースが追加または削除されている可能性があるため、必要です。
私は、キャッシュを最適化するために、ETag/If-Match を Last-Modified/If-Unmodified-Since と組み合わせて使用しています。ブラウザとプロキシは、キャッシュ アルゴリズムとして、これらのうちの 1 つまたは両方に依存している可能性があります。
検索/フィルター クエリが含まれていない限り、URL はクリーンであるべきだと思います。よく考えてみると、検索はコレクションの部分的な表示にすぎません。cars/search?q=BMW タイプの URL の代わりに、cars?manufacturer=BMW タイプの URL をもっと見るべきです。