30

より正確には:

残りのスタイルによると、POST、GET、PUT、および DELETE http メソッドを CREATE、READ、UPDATE、および DELETE (CRUD) 操作に使用する必要があると一般的に想定されています。

実際、http メソッドの定義に固執すると、それほど明確ではない可能性があります。

この記事では、次のように説明されています。

簡単に言えば、リソースが存在する URL とリソースのコンテンツ全体の両方がわかっている場合にのみ、PUT を使用してください。それ以外の場合は、POST を使用します。

主な理由

PUT はより限定的な動詞です。完全なリソースを受け取り、指定された URL に保存します。以前にリソースがあった場合は、置き換えられます。そうでない場合は、新しいものが作成されます。これらのプロパティはべき等性をサポートしていますが、単純な作成または更新操作ではサポートされていない可能性があります。これが、PUT がこのように定義されている理由であると思われます。これは、クライアントがサーバーに情報を送信できるようにするべき等操作です。

私の場合、通常はすべてのリソース データを渡す更新を発行するので、更新に PUT を使用できますが、更新を発行するたびに、LastUser 列と LastUpdate 列を、変更を行ったユーザー ID と操作の時刻と共に保存します。

厳密に言えば、これらの2つの列はリソースの一部ではありませんが、操作がべき等になるのを妨げているため、あなたの意見を知りたいです。

サルドス

サス

4

4 に答える 4

28

CRUDをHTTPメソッドにマッピングするRESTスタイルに関するコメントを無視すると、これは優れた質問です。

あなたの質問に対する答えは、はい、サーバーによって非べき等の方法で更新されるリソースのいくつかの要素がある場合でも、このシナリオではPUTを自由に使用できます。残念ながら、答えの背後にある理由はかなりあいまいです。重要なことは、クライアントの要求の意図が何であったかを理解することです。クライアントは、リソースの内容を渡された値で完全に置き換えることを意図していました。クライアントはサーバーが他の操作を行う責任を負わないため、HTTPメソッドのセマンティクスに違反することはありません。

これは、GET操作を実行するときにサーバーがページカウンターを更新できるようにするために使用される理由です。クライアントは更新を要求しなかったため、サーバーが更新を選択した場合でも、GETは安全です。

全体的な完全なリソースと部分的なリソースの議論は、HTTP仕様の更新でようやく詳しく説明されました。

オリジンサーバーは、Content-Rangeヘッダーフィールドを含むPUTリクエストを拒否する必要があります。これは、部分的なコンテンツとして誤って解釈される可能性があるためです(または、完全な表現として誤ってPUTされている部分的なコンテンツである可能性があります)。部分的なコンテンツの更新は、より大きなリソースの一部と重複する状態で個別に識別されたリソースをターゲットにするか、部分的な更新用に特別に定義された別のメソッド(たとえば、[RFC5789]で定義されたPATCHメソッド)を使用することで可能です。

だから、私たちがやるべきことは今や明確です。それほど明確ではないのは、完全な応答の送信のみを許可することにこの制約が存在する理由です。その質問は尋ねられました、そして、IMHOは残りの議論のこのスレッドで答えられないままです。

于 2011-04-16T13:54:36.943 に答える
9

LastUserとはクライアントが変更できないためLastUpdate、リソースの表現から完全に削除します。例を挙げて私の推論を説明しましょう。

単一のリソースを提供するように求められたときに、典型的な API の例がクライアントに次の表現を返すとします。

GET /example/123

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>ipsum</lorem>
    <dolor>sit amet</dolor>
    <lastUser uri="/user/321">321</lastUser>
    <lastUpdate>2011-04-16 20:00:00 GMT</lastUpdate>
</example>

クライアントがリソースを変更したい場合、おそらく表現全体を取り、それを API に送り返します。

PUT /example/123

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
    <lastUser>322</lastUser>
    <lastUpdate>2011-04-16 20:46:15 GMT+2</lastUpdate>
</example>

API は and の値を自動的に生成lastUserlastUpdate、クライアントから提供されたデータを受け入れることができないため、最も適切な応答は400 Bad Requestor403 Forbiddenです (クライアントはこれらの値を変更できないため)。

lastUserREST に準拠し、PUT 要求を実行するときにリソースの完全な表現を送信する場合は、リソースの表現からとを削除する必要がありlastUpdateます。これにより、クライアントは PUT 経由でエンティティ全体を送信できます。

PUT /example/123

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
</example>

lastUpdateおよびが含まれていないため、サーバーは完全な表現を受け入れるようになりlastUserます。

lastUpdate残っている問題は、クライアントにおよびへのアクセスを提供する方法lastUserです。彼らがそれを必要としない場合 (これらのフィールドは API によって内部的に必要とされるだけです)、私たちは問題なく、私たちのソリューションは完全に RESTful です。ただし、クライアントがこのデータにアクセスする必要がある場合、最もクリーンな方法は HTTP ヘッダーを使用することです。

GET /example/123

...
Last-Modified: Sat, 16 Apr 2011 18:46:15 GMT
X-Last-User: /user/322
...

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
</example>

カスタム HTTP ヘッダーの使用は、ユーザー エージェントに読み方を教える必要があるため、理想的ではありません。クライアントに同じデータへのアクセスをより簡単な方法で提供したい場合、私たちができる唯一のことはデータを表現に入れることであり、元の質問と同じ問題に直面しています。少なくとも何とか軽減しようと思います。API で使用されるコンテンツ タイプが XML の場合、データをノード値として直接公開するのではなく、ノード属性に入れることができます。つまり、次のようになります。

GET /example/123

...
Last-Modified: Sat, 16 Apr 2011 18:46:15 GMT
...

<?xml version="1.0" encoding="UTF-8" ?>
<example last-update="2011-04-16 18:46:15 GMT" last-user="/user/322">
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
</example>

このようにして、少なくとも、クライアントがフォローアップの PUT 要求ですべての XML ノードを送信しようとする問題を回避できます。これは JSON では機能せず、解決策はまだ冪等性の端にあります (API はリクエストを処理するときに XML 属性を無視する必要があるため)。

さらに良いことに、ジョナがコメントで指摘したように、クライアントがlastUserおよびにアクセスする必要がある場合lastUpdate、これらは新しいリソースとして公開され、元のリソースからリンクされます。たとえば、次のようになります。

GET /example/123

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
    <lastUpdateUri>/example/123/last-update</lastUpdateUri>
</example>

... その後:

GET /example/123/last-update

<?xml version="1.0" encoding="UTF-8" ?>
<lastUpdate>
    <resourceUri>/example/123</resourceUri>
    <updatedBy uri="/user/321">321</updatedBy>
    <updatedAt>2011-04-16 20:00:00 GMT</updatedAt>
</lastUpdate>

(リソースの変更ログが利用可能であれば、上記を適切に拡張して、個々の変更を含む完全な監査ログを提供することもできます。)

注: Darrel Miller質問に対する
見解 には同意しますが、その上で別のアプローチを提供したかったのです。このアプローチは、標準/RFC/などによってバックアップされていないことに注意してください。これは、問題に対する別の見方です。

于 2011-04-16T19:10:06.700 に答える
4

PUT を使用してリソースを作成することの欠点は、作成するオブジェクトを表す一意の ID をクライアントが提供する必要があることです。通常、クライアントがこの一意の ID を生成することは可能ですが、ほとんどのアプリケーション設計者は、サーバー (通常はデータベースを介して) がこの ID を作成することを好みます。ほとんどの場合、サーバーでリソース ID の生成を制御する必要があります。どうしようか?PUT の代わりに POST を使用するように切り替えることができます。

そう:

置く=更新

投稿 = 挿入

うまくいけば、これはあなたの特定のケースに役立ちます。

于 2011-04-16T13:03:54.970 に答える