DELETEリクエスト本文のRESTful代替


93

一方でHTTP 1.1仕様は、ように見えることを可能にメッセージ本文をDELETE要求、それのための定義された意味がないので、サーバはそれを無視すべきであることを示していると思われます。

4.3メッセージ本文

サーバーはどんなリクエストでもメッセージ本文を読んで転送すべきです。リクエストメソッドにエンティティボディの定義されたセマンティクスが含まれていない場合、リクエストを処理するときにメッセージボディを無視する必要があります(SHOULD)。

私はすでに、SOやそれ以降のこのトピックに関するいくつかの関連するディスカッションをレビューしました。

ほとんどの議論は、DELETEでメッセージ本文を提供することが許可されている可能性があることに同意しているようですが、一般的には推奨されません。

さらに、さまざまなHTTPクライアントライブラリの傾向に気づきました。DELETEのリクエスト本文をサポートするために、これらのライブラリのログ記録がますます強化されているようです。ほとんどのライブラリは義務的であるようですが、初期の抵抗が少しあることもあります。

私のユースケースでは、DELETEに必要なメタデータを追加する必要があります(たとえば、削除に必要な他のメタデータとともに、削除の「理由」)。私は次のオプションを検討しましたが、HTTP仕様やRESTのベストプラクティス、あるいはその両方と完全に一致しているようには見えません。

  • メッセージ本文 -仕様は、DELETEのメッセージ本文には意味論的な値がないことを示しています。HTTPクライアントでは完全にはサポートされていません。標準的な練習ではない
  • カスタムHTTPヘッダー -通常カスタムヘッダーを要求することは標準的な方法反します。それらの使用は、私のAPIの他の部分と一貫性がなく、いずれもカスタムヘッダーを必要としません。さらに、悪いカスタムヘッダー値を示すために利用できる適切なHTTP応答がありません(おそらく別の質問です)
  • 標準HTTPヘッダー -適切な標準ヘッダーはありません
  • クエリパラメータ - クエリパラメータを追加すると、削除されるRequest-URIが実際に変更されます。標準的な慣行に反して
  • POSTメソッド -(例POST /resourceToDelete { deletemetadata })POSTは削除のセマンティックオプションではありません。POSTは実際には反対のアクションを表します(つまり、POSTはリソースの下位を作成しますが、リソースを削除する必要があります)。
  • 複数のメソッド -DELETE要求を2つの操作(PUT削除メタデータ、次にDELETEなど)に分割すると、アトミック操作が2つに分割され、一貫性のない状態が残る可能性があります。削除理由(およびその他の関連メタデータ)は、リソース表現自体の一部ではありません。

私の最初の好みはおそらくカスタムHTTPヘッダーの次にメッセージ本文を使用することでしょう。ただし、示されているように、これらのアプローチにはいくつかの欠点があります。

DELETEリクエストにそのような必要なメタデータを含めるためのREST / HTTP標準に沿った推奨事項またはベストプラクティスはありますか?私が考慮していない他の選択肢はありますか?


2
などの特定の実装でJerseyは、deleteリクエストの本文を許可していません。
バジルハーム2013年

回答:


44

DELETE要求にメッセージ本文を使用しないようにいくつかの推奨事項がありますが、このアプローチは特定のユースケースで適切な場合があります。これは、質問/回答で言及された他のオプションを評価した後、およびサービスのコンシューマーと協力した後に私たちが最終的に使用したアプローチです。

メッセージ本文の使用は理想的ではありませんが、他のオプションのいずれも完全に適合していませんでした。リクエスト本文のDELETEにより、DELETE操作に必要な追加のデータ/メタデータの周りにセマンティクスを簡単かつ明確に追加できました。

私はまだ他の考えや議論にオープンですが、この質問のループを閉じたいと思いました。このトピックに関する皆さんの考えと議論に感謝します!


12
これは悪い考えです。これにより問題が発生するのは、後でAkamai EdgeConnectなどのHTTPアクセラレーションサービスを使用する場合です。EdgeConnectがHTTP DELETEリクエストからボディを削除するという事実を知っています(帯域幅を消費することはおそらく無効であるため)。同様のサービスが同じことをする可能性もあります(Kindleの高速化機能と他のCDNのようなサービスを参照してください)。サービスにHTTP動詞を使用しないように再設計する必要があります。ほとんどのAPIは、HTTP動詞/ classical-RESTを使用してもほとんど意味がなく、HTTP動詞のトランスポートの問題はトラブルシューティングが非常に困難です。
Gabe、2014年

3
@Gabeに同意します。定義上、ボディを持たないメソッドでボディを送信することは、ビットがインターネットパイプを通過するときにデータをランダムに失う確実方法であり、デバッグするのが非常に困難になります。
ニコラスシャンクス2014

3
DELETEの使用に対するこれらのコメントは、OPが持つ非常に有効な問題に対処するまで関係ありません。RESTの精神を守るために最善を尽くしていますが、現実的な状況では、楽観的な同時実行性のない削除や、アトミックバッチオペレーションがない削除は現実的ではありません。これは、RESTパターンの深刻な欠陥です。
Quarkly

私はこれについて@Quarklyと一緒にいます。同時実行性などをチェックする方法についてRESTFULの考え方がわかりません。同時実行性チェックはクライアントに属していません。
Dirk Wessels、

13

あなたが望んでいるように見えるのは2つのうちの1つであり、どちらも純粋ではありませんDELETE

  1. 2つの操作があります。1つPUTは削除理由で、次に1 DELETEがリソースです。削除すると、リソースのコンテンツには誰もアクセスできなくなります。「理由」には、削除されたリソースへのハイパーリンクを含めることはできません。または、
  2. あなたは、リソースを変更しようとしているからstate=activestate=deleted使用してDELETE方法を。state = deletedのリソースはメインAPIによって無視されますが、管理者またはデータベースアクセス権を持つユーザーは引き続き読み取り可能です。これは許可されDELETEています- リソースのバッキングデータを消去する必要はなく、そのURIで公開されているリソースを削除するだけです。

DELETEリクエストでメッセージ本文を必要とする操作は、最も一般的な、POSTメッセージ本文で必要なすべてのタスクを実行するa、およびに分類できますDELETE。HTTPのセマンティクスを壊す理由はないと思います。


2
場合はどうなるPUT理由が成功し、DELETEリソースに障害が発生しましたか?どのようにして矛盾した状態を防ぐことができますか?
ライトマン2017年

1
@Lightman PUTはインテントのみを指定します。対応するDELETEがなくても存在する可能性があります。これは、誰かが削除したかったが、失敗したか、気が変わったことを示します。呼び出しの順序を逆にすると、理由なしにDELETEを実行することもできます。理由の提供は、単なる注釈と見なされます。これらの両方の理由により、上記のオプション2を使用することをお勧めします。つまり、HTTPリソースが現在のURLから消えるように、基になるレコードの状態を変更します。その後、ガベージコレクター/管理者はレコードをパージできます
Nicholas Shanks

7

あなたの状況を踏まえて、私は次のいずれかのアプローチをとります。

  • PUTまたはPATCHを送信します。削除理由が必要な性質上、削除操作は仮想であると推測しています。したがって、PUT / PATCH操作によるレコードの更新は、それ自体はDELETE操作ではありませんが、有効なアプローチであると思います。
  • クエリパラメータを使用する:リソースのURIは変更されていません。これも有効なアプローチだと思います。リンクした質問は、クエリパラメータがない場合に削除を許可しないことについて話していました。あなたの場合、理由がクエリ文字列で指定されていない場合、デフォルトの理由があります。リソースはそのままですresource/:id。リソースのリンクヘッダーrelを使用して、理由ごとに(理由を特定するためのタグを使用して)検出可能にすることができます。
  • 理由ごとに別々のエンドポイント使用のようなURLを使用します:resource/:id/canceled。これは実際にRequest-URIを変更し、間違いなくRESTfulではありません。この場合も、リンクヘッダーはこれを発見可能にすることができます。

RESTは法律でもドグマでもないことに注意してください。ガイダンスとしてそれをもっと考えてください。したがって、問題のあるドメインのガイダンスに従わないことが理にかなっている場合は、従わないでください。APIコンシューマに差異が通知されていることを確認してください。


クエリパラメータの使用に関して、私の理解は、クエリがセクション3.2の Request-URIの一部であるため、このアプローチ(または同様に、個別のエンドポイント)を使用すると、DELETEリソースの定義に反することになります。Request-URIで識別される」が削除されます。
シェリー2013年

リソースは、uriパスによって識別されます。したがって、GET toはと/orders/:id同じリソースを返し/orders/:id?exclude=orderdetailsます。クエリ文字列は、サーバーにヒントを提供するだけです-この場合、応答でorderdetailsを除外します(サポートされている場合)。同様に、DELETEを/orders/:idor /orders/:id?reason=canceledまたはに送信する場合/orders/:id?reason=bad_creditでも、同じ基礎となるリソースを操作しています。「統一されたインターフェース」を維持するには、デフォルトの理由があるため、クエリパラメータを送信する必要はありません。
codeprogression 2013年

@shelleyクエリ文字列についてのあなたの懸念は正しいです。クエリ文字列はURIの一部です。DELETE要求をに送信すると、DELETEをに送信する/foo?123場合とは異なるリソースが削除されます/foo?456
ニコラスシャンクス2016年

@codeprogressionすみませんが、あなたが言うことの多くは間違っています。リソースは、パスだけでなくURI全体で識別されます。異なるクエリ文字列は異なるリソースです(HTTPの「リソース」という意味で)。また、統一されたインターフェースにはデフォルトの理由は必要ありません。この用語は、GET、PUT、POST、PATCH、DELETEをHTTPで定義された方法で使用することを指します。共通点はベンダー(ユーザーエージェントベンダー、APIベンダー、キャッシングプロキシベンダー、ISPなど)間であり、独自のAPI内ではありません(ただし、ユーザーの健全性のために設計が統一されている必要があります!)。
ニコラスシャンクス2016年

@Nicholas 3年前に終わった議論について議論する必要があるとは思いません。REST中心の観点から、私が行った回答とコメントは有効かつ正確です。RESTはHTTPではありません(HTTPのベンダーによる実装もありません)。RESTのコンテキストでは、リソースは同じです。そして、私の回答で述べたように、RESTは法律やドグマではなく、ガイダンスです。
codeprogression

0

必要なメタデータをURI階層自体の一部として含めることをお勧めします。例(ナイーブ):

開始日と終了日を本文またはクエリパラメータとして渡す代わりに、日付範囲に基づいてエントリを削除する必要がある場合は、必要な情報をURIの一部として渡すようにURIを構造化します。

例えば

DELETE /entries/range/01012012/31122012 -2012年1月1日から2012年12月31日までのすべてのエントリを削除します

お役に立てれば。


5
削除理由、つまりコメントフィールドの送信などのケースは対象外です。
Kugel 14

3
ワオ。それはひどい考えです。メタデータが多すぎると、URIのサイズ制限が膨れ上がります。
Balaji Boggaram Ramanarayan

1
このアプローチはRESTfulなプラクティスに従っていないため、複雑なURI構造になるため、お勧めしません。エンドポイントは、リソースIDとメタデータが絡み合って混乱し、APIが変更されると、やがてメンテナンスの悪夢になります。このrange質問の要であるクエリパラメータまたはペイロードで指定することは、はるかに好ましいです。私が言うには問題となるベストプラクティスアプローチを理解するのはこれではありません。
digitaldreamer 2016年

@digitaldreamer-複雑なURI構造の意味がわかりませんか?また、これはHTTP DELETEであるため、ペイロードはオプションではなくクエリパラメータです。
Suresh Kumar 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.