web-dev-qa-db-ja.com

タイムスタンプ属性も更新する場合、更新にPUTメソッドを使用する必要があります

より正確には:

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

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

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

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

主な理由は

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

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

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

サルド

sas

28
opensas

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

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

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

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

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

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

24
Darrel Miller

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

典型的なサンプル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はlastUserlastUpdateの値を自動的に生成し、クライアントから提供されたデータを受け入れることができないため、最も適切な応答は400 Bad Requestまたは403 Forbiddenになります(クライアントからこれらの値を変更することはできません)。

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

PUT /example/123

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

サーバーは、lastUpdatelastUserを含まないため、完全な表現を受け入れます。

残っている問題は、クライアントにlastUpdatelastUserへのアクセスを提供する方法です。彼らがそれを必要としない場合(そしてこれらのフィールドは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属性を無視する必要があるため)。

さらに良いことに、コメントで Jonah が指摘しているように、クライアントがlastUserlastUpdateにアクセスする必要がある場合、これらは元のリソースからリンクされた新しいリソースとして公開できます。 1つの例次のように:

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などによってバックアップされていないことに注意してください。これは、問題に対する別の見方にすぎません。

8
MicE

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

そう:

置く=更新

投稿=挿入

うまくいけば、これはあなたの特定のケースに役立つでしょう。

4
Cristian Boariu

HTTPメソッドPOSTとPUTは、CRUDの作成と更新に相当するHTTPではありません。どちらも目的が異なります。PUTを使用することは非常に可能であり、有効であり、場合によっては推奨されます。リソースを作成するか、POSTを使用してリソースを更新します。

特定のリソースを介してリソースを完全に更新できる場合は、PUTを使用します。たとえば、記事が http://example.org/article/1234 にあることがわかっている場合は、このURLのPUTを介して、この記事の新しいリソース表現を直接PUTできます。

たとえば、新しい記事を追加するときに実際のリソースの場所がわからないが、どこに保存するかわからない場合は、URLにPOSTして、サーバーが実際のURLを決定します。

0
Anil