REST-IDを本文に入れるかどうか


96

クライアントがIDを割り当てることができる人のためのRESTfulリソースが欲しいとしましょう。

人は次のようになります。 {"id": <UUID>, "name": "Jimmy"}

さて、クライアントはそれをどのように保存(または "PUT")すべきでしょうか?

  1. PUT /person/UUID {"id": <UUID>, "name": "Jimmy"} -これで、常に検証する必要があるこの厄介な重複があります。本文のIDがパスのIDと一致していますか?
  2. 非対称表現:
    • PUT /person/UUID {"name": "Jimmy"}
    • GET /person/UUID 戻り値 {"id": <UUID>, "name": "Jimmy"}
  3. 本文にIDがありません-IDは場所のみにあります:
    • PUT /person/UUID {"name": "Jimmy"}
    • GET /person/UUID 戻り値 {"name": "Jimmy"}
  4. POSTIDはクライアントによって生成されるので、良い考えとは思えません。

一般的なパターンとそれを解決する方法は何ですか?ロケーションのみのIDは最も独断的に正しい方法のように思われますが、実際の実装も難しくなります。

回答:


62

さまざまな読み取り/書き込みモデルを使用しても問題はありません。クライアントは1つのリソース表現を書き込むことができます。サーバーは、追加/計算された要素を含む別の表現を返すことができます(または完全に異なる表現であっても、それに対する仕様には何もありません)。 、唯一の要件は、PUTがリソースを作成または置換する必要があることです)。

したがって、私は(2)の非対称ソリューションを採用し、サーバー側での「厄介な重複チェック」を避けて記述します。

PUT /person/UUID {"name": "Jimmy"}

GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}

2
タイピング(静的または動的)を適用すると、IDのないモデルを簡単に作成することはできません... PUTリクエストのURLからIDを削除する方がはるかに簡単です。それは「落ち着いた」ものではありませんが、それは正しいでしょう。
Ivan Kleshnin 2016

2
追加のTOをid、IDとエンティティのTO、追加のコンバーター、およびプログラマーにとって大きすぎるオーバーヘッドなしで保持します。
グリゴリーキスリン

BODYからIDを取得した場合の例:PUT / person {"id":1、 "name": "Jimmy"}。それは悪い習慣でしょうか?
Bruno Santos

本文にIDを入れても問題ありません。IDには整数ではなくGUIDを使用してください。そうしないと、IDが重複するリスクがあります。
ジョーンWildt

これは間違っています。私の答えを見てください。PUTにはリソース全体が含まれている必要があります。IDを除外してレコードの一部のみを更新する場合は、PATCHを使用します。
CompEng88

27

それがパブリックAPIである場合、返信するときは控えめにする必要がありますが、寛大に受け入れてください。

つまり、1と2の両方をサポートする必要があります。3は意味がないことに同意します。

1と2の両方をサポートする方法は、リクエストの本文に何も指定されていない場合はURLからIDを取得し、リクエストの本文にある場合は、URLのIDと一致することを検証することです。2つが一致しない場合は、400 Bad Request応答を返します。

個人用リソースを返す場合は、保守的にし、プットではオプションですが、常にjsonにIDを含めます。


3
これは受け入れられる解決策です。APIは常にユーザーフレンドリーでなければなりません。本文ではオプションにする必要があります。POSTからIDを受け取ってはならず、PUTで​​未定義にする必要があります。また、作成された400応答ポイントは正解です。
マイケル

約400コードは、softwareengineering.stackexchange.com / questions / 329229 /…の説明も参照してください。ショートA 400コードは、不適切なだけ少ない特異的ではない422に比較
グリゴリーKislin

8

この問題の1つの解決策には、「アプリケーション状態のエンジンとしてのハイパーテキスト」または「HATEOAS」というやや混乱する概念が含まれます。つまり、REST応答には、ハイパーリンクとして実行される利用可能なリソースまたはアクションが含まれます。RESTの当初の概念の一部であったこの方法を使用すると、リソースの一意の識別子/ ID自体がハイパーリンクになります。したがって、たとえば、次のようにすることができます。

GET /person/<UUID> {"person": {"location": "/person/<UUID>", "data": { "name": "Jimmy"}}}

次に、そのリソースを更新する場合は、(疑似コード)を実行できます。

updatedPerson = person.data
updatedPerson.name = "Timmy"
PUT(URI: response.resource, data: updatedPerson)

これの1つの利点は、クライアントがサーバーのユーザーIDの内部表現について何の考えも持つ必要がないことです。クライアントがIDを検出する方法を持っている限り、IDは変更され、URL自体も変更される可能性があります。たとえば、人々のコレクションを取得する場合、次のような応答を返すことができます。

GET /people
{ "people": [
    "/person/1",
    "/person/2"
  ]
}

(もちろん、アプリケーションのニーズに応じて、各人物の完全な人物オブジェクトを返すこともできます)。

この方法を使用すると、リソースや場所の観点からオブジェクトのことを考え、IDの観点からは考えません。したがって、一意の識別子の内部表現はクライアントロジックから切り離されます。これはRESTの背後にある最初の推進力でした。HTTPの機能を使用して、以前に存在したRPCシステムよりも疎結合のクライアントサーバーアーキテクチャを作成することです。HATEOASの詳細については、ウィキペディアの記事とこの短い記事をご覧ください


4

挿入では、URLにIDを追加する必要はありません。このように、PUTで​​IDを送信すると、主キーを変更するためにUPDATEとして解釈される場合があります。

  1. インサート:

    PUT /persons/ 
      {"id": 1, "name": "Jimmy"}
    HTTP/1.1 201 Created     
      {"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}
    
    GET /persons/1
    
    HTTP/1.1 200 OK
      {"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}  
    
  2. 更新

    PUT /persons/1 
         {"id": "2", "name": "Jimmy Jr"} - 
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="filled_by_server"}
    
    GET /persons/2 
    
    HTTP/1.1 200 OK
         {"id": "2", "name": "Jimmy Jr", "other_field"="updated_by_server"}
    

JSON APIは、この規格を使用して、新しいオブジェクトへのリンクを挿入または更新されたオブジェクトを返すいくつかの問題を解決します。一部の更新または挿入には、追加のフィールドを変更するビジネスロジックが含まれている場合があります

また、挿入および更新後の取得を回避できることもわかります。


3

これは以前に尋ねられました-議論は一見の価値があります:

RESTful GET応答はリソースのIDを返す必要がありますか?

これは、「RESTful」とそうでないものについての議論に行き詰まりやすい質問の1つです。

価値があることについては、一貫したリソースの観点から考え、メソッド間でそれらのデザインを変更しないようにしています。ただし、ユーザビリティの観点から最も重要なことは、API全体で一貫しているということです。


2

操作ごとに異なる表現を使用することは問題ありませんが、PUTの一般的な推奨事項は、WHOLEペイロードを含めることです。つまり、それidもそこにあるはずです。それ以外の場合は、PATCHを使用する必要があります。

そうは言っても、PUTは主に更新に利用し、もid常にURLで渡す必要があると思います。その結果、リソース識別子を更新するためにPUTを使用することは悪い考えです。idURLとid本文のが異なる場合は、望ましくない状況になります。

では、どうすればこのような矛盾を解決できるでしょうか。基本的に2つのオプションがあります。

  • 4XX例外をスローする
  • WarningX-API-Warnetc)ヘッダーを追加します。

このトピックは一般に意見の問題なので、これはこの質問に答えるのに可能な限り近いです。


2

参考までに、ここでの答えは間違っています。

見る:

https://restfulapi.net/rest-api-design-tutorial-with-example/

https://restfulapi.net/rest-put-vs-post/

https://restfulapi.net/http-methods/#patch

置く

主に既存のリソースを更新するためにPUT APIを使用します(リソースが存在しない場合、APIは新しいリソースを作成するかどうかを決定する場合があります)。PUT APIによって新しいリソースが作成された場合、配信元サーバーはHTTP応答コード201(Created)応答を介してユーザーエージェントに通知する必要があり、既存のリソースが変更された場合は200(OK)または204(No Content)のいずれかです。要求が正常に完了したことを示すために、応答コードを送信する必要があります(SHOULD)。

リクエストがキャッシュを通過し、Request-URIが現在キャッシュされている1つ以上のエンティティを識別する場合、それらのエントリは古いものとして扱われる必要があります(SHOULD)。このメソッドへの応答はキャッシュできません。

リソースコレクションの一部である単一のリソースを変更する場合は、PUTを使用します。PUTはリソース全体を置き換えます。リクエストがリソースの一部を更新する場合は、PATCHを使用します。

パッチ

HTTP PATCHリクエストは、リソースを部分的に更新することです。PUTリクエストでリソースエンティティも変更されているため、より明確になる場合– PATCHメソッドは、既存のリソースを部分的に更新するための正しい選択です。PUTは、リソース全体を置き換える場合にのみ使用してください。

したがって、次のように使用する必要があります。

POST    /device-management/devices      : Create a new device
PUT     /device-management/devices/{id} : Update the device information identified by "id"
PATCH   /device-management/devices/{id} : Partial-update the device information identified by "id"

RESTfulプラクティスでは、/ {id}で何をPUTするかは問題ではないことを示しています。レコードのコンテンツは、ペイロードによって提供されるものに更新する必要がありますが、GET / {id}は同じリソースにリンクする必要があります。

つまり、PUT / 3はペイロードIDを4に更新しますが、GET / 3は同じペイロードにリンクする必要があります(IDが4に設定されたペイロードを返します)。

APIがURIとペイロードで同じ識別子を必要とすると決めた場合、それが一致することを確認するのはあなたの仕事ですが、完全に存在するはずのペイロードのIDを除外する場合は、必ずPUTではなくPATCHを使用してください。 。これは、受け入れられた答えが間違っているところです。PUTはリソース全体を置き換える必要があります。パッチは部分的な場合もあります。


1

さまざまなアプローチを使用しても何も悪いことはありません。しかし、私は最良の方法は2番目の解決策だと思います。

 PUT /person/UUID {"name": "Jimmy"}

 GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}

エンティティフレームワークがdbContextに追加されたときにエンティティフレームワークがこの手法を使用する場合も、この方法主に使用されます。生成されたIDのないクラスは、エンティティフレームワークの参照によって生成されたIDです。


1

これをJSON-LD /セマンティックWebの観点から見ています。これは、これらのスライドで説明したように、実際のREST準拠を実現するための良い方法だからです。その観点から見ると、WebリソースのID(IRI)は常に、リソースの検索/逆参照に使用できるURLと等しいはずなので、オプション(1.)に進むのは間違いありません。検証は実装するのが本当に難しいことでも、計算量が多いことでもないと思います。だから私はこれをオプション(2.)で進める正当な理由だとは思わない。POST(新規作成)はPUT(更新/置換)とは異なるセマンティクスを持っているため、オプション(3.)は実際にはオプションではないと思います。


0

PATCH / PUTリクエストタイプを調べる必要がある場合があります。

PATCHリクエストは、リソースを部分的に更新するために使用されますが、PUTリクエストでは、サーバー上でオーバーライドされるリソース全体を送信する必要があります。

URLにIDを含めることに関しては、リソースを識別するのは標準的な方法であるため、常にIDを用意する必要があると思います。Stripe APIも同様に機能します。

PATCH要求を使用して、サーバー上のリソースをIDで更新して識別できますが、実際のIDは更新しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.