8

リソースの表現が不完全な PUT に期待される標準的な動作は何ですか?

たとえば、以下の HAL json で表されるUserat があります。/api/users/1

{'id': 1,
 'username': 'joedoe',
 'email': 'joe@doe.com',
 'password_hash': '9039dmk38f84uf4029i339kf32f0932i',
 'last_visit': '2013-11-04 21:09:01',
 'public': true,
 '_links': {'self': {'href': 'http://foo.bar.com/api/users/1'}}

}

次に、他の属性が欠落している表現を使用して、usernameandを変更する PUT リクエストを作成します。email

PUT /api/users/1

{'username': 'joeydoey',
 'email': 'joey@doey.com'}

これまでは、これは部分的な更新を意味するため、エラーとして扱われるべきだと常に思っていましたが、この回答は私にそれについて考えさせました。デフォルトで空白を埋める自由。

HTTP標準でこれに関連するものを見つけることができないので、この場合に期待される標準化された動作は何ですか?

  1. 部分的な更新を意味するため、エラーが発生するはずです。PUT ペイロードのスキーマは、同じリソースおよびメディア タイプへの GET で取得されたスキーマと同一である必要があります。

  2. サーバーはそのメディア タイプのデフォルトで空白を自由に埋めることができるため、成功するはずです。この場合、パスワードを空白またはデフォルトのパスワードにリセットし、それに応じてハッシュを更新し、last_visit と public の値をデフォルトに設定します。このオプションは、クライアントがサーバーから返されたのと同じメディア タイプを送信している場合、HATEOAS を考慮するとより意味があります。すべてのハイパーリンクを送信するわけではなく、サーバーはそれに応じてハイパーリンクをリセットする必要があります。

  3. 1 と 2 の両方が有効です。これは、標準化された動作がなく、それをどうするかを決定するのはメディアの種類次第であるためです。PUT はリソース自体に従属するのではなく、リソースを置き換えるため、これは適切ではありません。

何が正しいと感じるか、何が理にかなっているのかを尋ねているわけではないことに注意してください。どちらが標準に準拠しているかを尋ねています。

4

2 に答える 2

5

PUT の結果がクライアントのリソースの理解から完全に置き換えられている限り (つまり、渡されなかったプロパティの以前の値は、PUT 後の値に影響しません)、成功するはずです。ただし、非常に多くの人がこの PUT の使用をフィールド レベルの更新セマンティクス (完全な置換ではなく) とあいまいにする傾向があるため、これを見ると少し混乱します。

ここで技術的に REST 制約に違反することはありませんが、すべての値を渡し、サーバーの既定値に頼らない方がおそらく良い考えです。これにより、前方互換性が維持されます。デフォルトは時間の経過とともに変化する可能性があるため、通常は避ける必要があります。

ただし、リンクの例は、デフォルトを渡さないことについて言及していないため、「不完全な表現」の良い例ではありません。むしろ、リンクは、サーバーに対するクライアントのリソース表現の一部ではありません。ここで別の概念を取り入れていると思います:サーバーからクライアントにのみ返されるプロパティです。これは、この投稿のきっかけとなった別のスレッドで私が話していたことです。

私が話しているのは不完全な表現ではありません。それは別の表現です。実際には、同じリソースを記述する 2 つの異なるメディア タイプ (つまり、表現) を扱っています。1 つはクライアントから発生し (application/vnd.example.api.client と呼びます)、もう 1 つはサーバーから発生します (application/vnd.example.api.server)。それらは明示的にそのようにラベル付けされていないかもしれませんが、それは少なくとも暗黙のうちに起こっていることです. したがって、これらは 2 つの異なるメディア タイプであるため、同じリソースについて異なることを表現します。

HAL について言及したので、クライアントは通常、メディア タイプ application/hal+json のメッセージをサーバーに POST しないと考えてください。例として、HALTalk のサインアップ rel を見てください。予期されるコンテンツ タイプは、application/hal+json ではなく、application/json です。そして、サンプル投稿を見ると、HAL っぽいものは何もありません。リンクや埋め込みオブジェクトなどはありません。しかし...この POST から返された Location ヘッダーから返された URL を取得すると、クライアントが JSON 経由で HAL を受け入れると仮定すると、タイプ application/hal+json の応答が返されます。 (つまり、リンクを持つユーザー)。2 つの異なるメディア タイプ、同じリソースの 2 つの異なる表現。

したがって、私の要点を説明するために、例を Accept および Content-Type ヘッダーで装飾させてください。

リクエスト

PUT /api/users/1 HTTP/1.1
Content-Type: application/vnd.example.api.client+json

{'username': 'joeydoey',
 'email': 'joey@doey.com'}

応答

200 OK
Content-Type: application/hal+json;profile=application/vnd.example.api.server

{'id': 1,
 'username': 'joeydoey',
 'email': 'joey@doey.com',
 'password_hash': '9039dmk38f84uf4029i339kf32f0932i',
 '_links': {'self': {'href': 'http://foo.bar.com/api/users/1'}}
}

ほとんどのシステムは、メディアの種類を説明するためにこれほど詳細に説明することはありません。通常は、より一般的なタイプ (application/json や 1 つのカスタム メディア タイプのみなど) にフレーム化されています。ただし、これは基本的なリソースは同じですが、これらは 2 つの異なる表現であるという事実に変わりはありません。わかる?

于 2013-11-07T04:43:19.833 に答える