web-dev-qa-db-ja.com

RESTful API。作成/更新されたオブジェクトを返す必要がありますか?

私はWebApiを使用してRESTful Webサービスを設計していて、オブジェクトの更新/作成時に返すHTTP応答と応答本文を考えていました。

たとえば、POSTメソッドを使用して、JSONをWebサービスに送信し、オブジェクトを作成することができます。HTTPステータスを作成済み(201)またはok(200 )そして単に「新しい従業員が追加されました」などのメッセージを返すか、元々送信されたオブジェクトを返しますか?

同じことがPUTメソッドにも当てはまります。使用するのに最適なHTTPステータスはどれですか。作成されたオブジェクトまたは単なるメッセージを返す必要がありますか?とにかく、ユーザーが作成/更新しようとしているオブジェクトを知っているという事実を考慮してください。

何かご意見は?

例:

新しい従業員を追加:

POST /api/employee HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
    "Employee": {
        "Name" : "Joe Bloggs",
        "Department" : "Finance"
    }
}

既存の従業員を更新:

PUT /api/employee HTTP/1.1
Host: localhost:8000
Content-Type: application/json

{
    "Employee": {
        "Id" : 1
        "Name" : "Joe Bloggs",
        "Department" : "IT"
    }
}

応答:

オブジェクトが作成/更新された応答

HTTP/1.1 201 Created
Content-Length: 39
Content-Type: application/json; charset=utf-8
Date: Mon, 28 Mar 2016 14:32:39 GMT

{
    "Employee": {
        "Id" : 1
        "Name" : "Joe Bloggs",
        "Department" : "IT"
    }
}

メッセージのみの応答:

HTTP/1.1 200 OK
Content-Length: 39
Content-Type: application/json; charset=utf-8
Date: Mon, 28 Mar 2016 14:32:39 GMT

{
    "Message": "Employee updated"
}

ステータスコードのみの応答:

HTTP/1.1 204 No Content
Content-Length: 39
Date: Mon, 28 Mar 2016 14:32:39 GMT
44
iswinky

ほとんどの場合と同様に、状況によって異なります。トレードオフは、使いやすさとネットワークサイズです。クライアントが作成されたリソースを確認することは非常に役立ちます。これには、last-creation-timeなど、サーバーによって入力されたフィールドが含まれる場合があります。 idを使用する代わりにhateoasを含めているように見えるため、クライアントはおそらくPOSTedしたリソースのIDを確認する必要があります。

作成したリソースを含めない場合は、任意のメッセージを作成しないでください。 2xxフィールドとLocationフィールドは、クライアントが要求が適切に処理されたと確信するのに十分な情報です。

38
Eric Stein

個人的に、私はalwaysのみを返します200 OK

あなたの質問を引用するには

とにかく、ユーザーが作成/更新しようとしているオブジェクトを知っているという事実を考慮してください。

すでに知っていることをクライアントに伝えるために、追加の帯域幅(有料にする必要があるかもしれません)を追加するのはなぜですか?

リンク RFC規格 を参照すると、Postを使用して要求リソースを正常に格納すると、201(作成済み)ステータスが返されます。ほとんどのアプリケーションでは、リソースのIDはサーバー自体によって生成されるため、作成されたリソースのIDを返すことをお勧めします。オブジェクト全体を返すことは、Postリクエストのオーバーヘッドです。理想的な方法は、新しく作成されたリソースのRLの場所を返すです。

たとえば、従業員オブジェクトをデータベースに保存し、新しく作成されたリソースオブジェクトのURLを応答として返す次の例を参照できます。

@RequestMapping(path = "/employees", method = RequestMethod.POST)
public ResponseEntity<Object> saveEmployee(@RequestBody Employee employee) {
        int id = employeeService.saveEmployee(employee);
        URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(id).toUri();
        return ResponseEntity.created(uri).build();
}

この残りのエンドポイントは、次のような応答を返します。

ステータス201-作成済み

ヘッダーの場所→ http:// localhost:8080/employees/1

10

@iswinky POSTとPUTの両方の場合、私は常にペイロードを送り返します。

POSTの場合、内部IDまたはUUIDでエンティティを作成する可能性があります。そのため、ペイロードを送り返すことは理にかなっています。

同様に、PUTの場合、ユーザーの一部のフィールド(たとえば、不変値)を無視するか、PATCHの場合、データが他のユーザーによっても変更されている可能性があります。

永続化された状態でデータを返送することは常に良い考えであり、間違いなく害はありません。呼び出し元がこの返されたデータを必要としない場合、呼び出し元はそれを処理せず、単にstatusCodeを消費します。そうでなければ、UIを更新するためにこのデータを使用できます。

DELETEの場合にのみ、ペイロードを返送せず、応答コンテンツで200を実行するか、応答コンテンツなしで204を実行します。

編集:下からのコメントのおかげで、私は私の答えを書き直しています。私はまだ自分のAPIを設計して応答を返す方法を待機していますが、設計の考えの一部を限定することは理にかなっていると思います。

a)ペイロードを送り返すと言った場合、実際には、リクエストで受け取ったのと同じペイロードではなく、リソースのデータを送り返すことを意味しました。例:作成ペイロードを送信すると、バックエンドでUUIDや(たぶん)タイムスタンプ、一部の(グラフ)接続などの他のエンティティが作成される場合があります。私はこれをすべて応答で返します(要求のペイロードだけではなく、これは無意味です)。

b)ペイロードが非常に大きい場合は、応答を返しません。これについてはコメントで説明しましたが、注意が必要なのは、非常に大きなペイロードを必要としないようにAPIまたはリソースを設計するために最善を尽くすことです。私は、リソースをより小さく管理しやすいエンティティに分割して、各リソースが15〜20のJSON属性で定義され、それより大きくはならないようにします。

オブジェクトが非常に大きい場合、または親オブジェクトが更新されている場合は、ネストされた構造をhrefとして送り返します。

結論としては、コンシューマー/ UIが即座に処理し、アトミックなAPIアクションで実行できるデータを送り返して、UIを更新するためだけに2〜5個のAPIをフェッチする必要はなく、データの作成/更新。

サーバーからサーバーへのAPIは、これについて異なる考え方をする場合があります。ユーザーエクスペリエンスを促進するAPIに焦点を当てています。

10
ksprashu

私は、HTTPパラメーターを条件とする戻り本文のペイロードを作成します。

多くの場合、不必要なラウンドトリップ(GraphQLが存在する理由の1つ)を回避するために、ある種のコンテンツをAPIコンシューマーに返すのが最善です。

実際のところ、アプリケーションのデータ集約化と分散化が進むにつれて、次のガイドラインを遵守するようにしています。

マイガイドライン

POSTまたはPUTの直後にGETを要求するユースケースがある場合は常に、単にPOST/PUT応答で何かを返すことが最善の場合です。

これがどのように行われるか、およびPUTまたはPOSTから返されるコンテンツのタイプは、アプリケーション固有です。ここで、アプリケーションが応答本文の「コンテンツ」のタイプをパラメーター化できると興味深いでしょう(新しいオブジェクトの場所、一部のフィールド、またはオブジェクト全体などが必要ですか)。

アプリケーションは、POST/PUTが受信できる一連のパラメーターを定義して、応答本文で返す「コンテンツ」のタイプを制御できます。あるいは、ある種のGraphQLクエリをパラメーターとしてエンコードすることもできます(これは有用であることがわかりますが、メンテナンスの悪夢にもなります)。

いずれにせよ、私には次のように思われます。

  1. POST/PUTレスポンスボディで何かを返すことは問題ありません(そしておそらく望ましいことです)。
  2. これがどのように行われるかはアプリケーション固有であり、一般化することはほとんど不可能です。
  3. デフォルトでは大きなサイズの「コンテキスト」を返したくない(GET-POST-followed-by-GETsから離れる理由全体を打ち消すトラフィックノイズ)。

したがって、1)それを実行しますが、2)単純にしてください。

私が見たもう1つのオプションは、別のエンドポイントを作成する人々です(たとえば、POST/PUTの/ customersは本体に何も返さず、POST/PUTの/ customer_with_detailsは/ customersに返されますが、応答本体に何かを返します)。

ただし、このアプローチは避けます。異なる種類のコンテンツを正当に返す必要がある場合はどうなりますか?コンテンツタイプごとに1つのエンドポイント?スケーラブルまたは保守可能ではありません。

0
luis.espinal