REST Complex / Composite / Nested Resources [終了]


177

RESTベースのAPIで概念に対処するための最良の方法に頭を抱えようとしています。他のリソースを含まないフラットリソースは問題ありません。問題が発生しているのは複雑なリソースです。

たとえば、漫画のリソースがあります。ComicBookその上のプロパティのすべての種類などを有しているauthorissue numberdate、など

漫画本にも1..nカバーのリストがあります。これらのカバーは複雑なオブジェクトです。これらには、カバーに関する多くの情報が含まれています。アーティスト、日付、さらにはBase 64でエンコードされたカバーの画像です。

以下のためGETComicBook私は漫画を返し、そのbase64'ed画像を含むカバーのすべての可能性があります。それはおそらく単一の漫画を得るために大したことではありません。しかし、システム内のすべてのコミックを表にリストしたいクライアントアプリを作成しているとします。
テーブルにはComicBookリソースのいくつかのプロパティが含まれますが、テーブル内のすべてのカバーを表示する必要はありません。1000冊のコミックを返し、それぞれに複数のカバーがあると、回線上に途方もなく大量のデータが送られてきます。この場合、エンドユーザーには不要なデータです。

私の本能はCover、リソースを作成し、ComicBookカバーを含めることです。これCoverがURIです。GETコミック本では今では機能しますが、巨大なCoverリソースの代わりに、各カバーのURIを返信し、クライアントは必要に応じてカバーリソースを取得できます。

今、私は新しい漫画を作ることに問題があります。確かに、を作成するときに少なくとも1つのカバーを作成する必要がありますComic。実際、これはおそらくビジネスルールです。
だから私は行き詰まっています、私は最初にを送信してCoverそのカバーのURIを取得し、次にリストにそのURIを付けてを送信することによってクライアントにビジネスルールを適用するよう強制POSTするComicBookか、またはPOSTon ComicBookはそれが吐き出すのとは異なる見た目のリソースを受け取りますでる。着信リソースPOSTとはGET、発信深いコピー、あるGETsが依存リソースへの参照が含まれています。

Cover私はいくつかのケースでは、アドレスカバー方向にしたいと思いクライアントとして確信しているので、リソースがどのような場合には、おそらく必要があります。そのため、依存するリソースのサイズに関係なく、問題は一般的な形で存在します。一般に、クライアントにそれらのリソースがどのように構成されているかを「知る」ことを強制せずに、複雑なリソースをどのように処理しますか?


RESTFUL SERVICE DISCOVERYを使用する意味はありますか?
ツリーコーダー2011

1
私はHATEAOSに固執しようとしています。私の考えでは、そのようなものを使用することに対抗しますが、私は見ていきます。
jgerman

同じ精神で異なる質問。ただし、所有権は提案されたソリューション(問題の1つ)とは異なります。stackoverflow.com/questions/20951419/...
ウェス・

回答:


64

@ray、素晴らしい議論

@jgermanは、RESTであることを忘れないでください。リソースをPOSTから設定する必要があるという意味ではありません。

リソースの特定の表現に含めるものを選択するのは、あなた次第です。

個別に参照されるカバーのケースは、子リソース(カバー)が相互参照される可能性がある親リソース(コミックブック)の作成にすぎません。たとえば、著者、出版社、キャラクター、またはカテゴリへの参照を個別に提供することもできます。これらのリソースを個別に、または子リソースとして参照する漫画本の前に作成することもできます。または、親リソースの作成時に新しい子リソースを作成することもできます。

カバーの具体的なケースは、カバーが実際に漫画本を必要とし、その逆もあるので、少し複雑です。

ただし、電子メールメッセージをリソースと見なし、差出人アドレスを子リソースと見なす場合でも、差出人アドレスを個別に参照できることは明らかです。たとえば、アドレスからすべて取得します。または、以前の差出人アドレスを使用して新しいメッセージを作成します。メールがRESTの場合、相互参照された多くのリソース(/ received-messages、/ draft-messages、/ from-addresses、/ to-addresses、/ addresses、/ subjects、/ attachments、/ folders)が利用可能であることが簡単にわかります、/ tags、/ categories、/ labelsなど

このチュートリアルは、相互参照されたリソースの優れた例を提供します。 http://www.peej.co.uk/articles/restfully-delicious.html

これは、自動生成されたデータの最も一般的なパターンです。たとえば、新しいリソースのURI、ID、作成日はサーバーによって生成されるため、投稿しないでください。さらに、新しいリソースを取得するときに、URI、ID、または作成日を取得できます。

バイナリデータの例。たとえば、バイナリデータを子リソースとして投稿するとします。親リソースを取得すると、それらの子リソースを同じバイナリデータとして、またはバイナリデータを表すURIとして表すことができます。

フォームとパラメータは、リソースのHTML表現とはすでに異なります。URLを生成するバイナリ/ファイルパラメータの投稿は、ストレッチではありません。

新しいリソースのフォーム(/ comic-books / new)を取得するとき、またはリソースを編集するフォーム(/ comic-books / 0 / edit)を取得するときは、リソースのフォーム固有の表現を要求します。content-typeが「application / x-www-form-urlencoded」または「multipart / form-data」のリソースコレクションに投稿した場合、その型表現を保存するようサーバーに要求しています。サーバーは、保存されたHTML表現などで応答できます。

また、APIなどの目的で、HTML、XML、またはJSON表現をリソースコレクションに投稿できるようにすることもできます。

コミックの後に投稿されたカバーを考慮に入れて、コミックブックにカバーを要求することを考慮して、リソースやワークフローを表現することもできます。以下の例。

  • カバーの作成を遅らせることができます
  • 必要なカバーを付けてコミックブックを作成できます
  • カバーを相互参照できるようにします
  • 複数のカバーが可能
  • ドラフトコミックブックを作成する
  • 漫画本のドラフトを作成する
  • 下書きの漫画本を公開する

GET / comic-books
=> 200 OK、すべての漫画本を取得します。

GET / comic-books / 0
=> 200 OK、カバー(/ covers / 1、/ covers / 2)付きのコミック(ID:0)を取得します。

GET / comic-books / 0 / covers
=> 200 OK、コミックブックのカバーを取得します(ID:0)。

GET / covers
=> 200 OK、すべてのカバーを取得します。

GET / covers / 1
=> 200 OK、コミック(/ comic-books / 0)のカバー(ID:1)を取得します。

GET / comic-books / new
=> 200 OK、フォームを取得してコミックブックを作成します(フォーム:POST / draft-comic-books)。

POST / draft-comic-books
title = foo
author = boo
publisher = goo
published = 2011-01-01
=> 302見つかりました、場所:/ draft-comic-books / 3、ドラフトコミックブック(ID:3)にリダイレクトしますカバー(バイナリ)。

GET / draft-comic-books / 3
=> 200 OK、カバー付きのドラフトコミックブック(ID:3)を取得します。

GET / draft-comic-books / 3 / covers
=> 200 OK、ドラフトコミックブックのカバーを取得(/ draft-comic-book / 3)。

GET / draft-comic-books / 3 / covers / new
=> 200 OK、フォームを取得してドラフトコミックのカバーを作成(/ draft-comic-book / 3)(フォーム:POST / draft-comic-books / 3 /カバー)。

POST / draft-comic-books / 3 / covers
cover_type = front
cover_data =(binary)
=> 302が見つかりました、場所:/ draft-comic-books / 3 / covers、ドラフトコミックの新しいカバーにリダイレクト(/ draft-comic -book / 3 / covers / 1)。

GET / draft-comic-books / 3 / publish
=> 200 OK、Getフォームを取得してドラフトコミックブックを発行します(id:3)(form:POST / published-comic-books)。

POST / published-comic-books
title = foo
author = boo
publisher = goo
published = 2011-01-01
cover_type = front
cover_data =(binary)
=> 302見つかりました、場所:/ comic-books / 3、公開されたコミックブックにリダイレクトします(ID:3)カバー付き。


私はこれがまったくの初心者で、急いでそれを学ぼうとしています。これは非常に役に立ちました。しかし、私が今日読んでいる他のブログなどでは、操作(特にべき等ではない操作)を実行するためのGETの使用は好ましくないでしょう。それでそれはPOST / draft-comic-books / 3 / publishであるべきではありませんか?
ゲイリーマギル2012

3
@GaryMcGill彼の例では、/ draft-comic-books / 3 / publishはHTMLフォームのみを返します(データを変更しません)。
Olivier Lalonde、2012年

@Olivierは正しいです。publishという単語は、フォームが何をするかを示すためにあります。ただし、動詞をHTTPメソッドに限定したいので、発行された漫画本のリソースに投稿する必要があります。...これがWebサイトの場合、フォームが何かを公開するためのURIが必要になる場合があります。...ただし、パブリッシュアクションがコミックページの単一のボタンである場合、その単一ボタンのフォームは/ published-comic-books URIに直接投稿できます。
アレックス

@ Alex、POSTリクエストで、代わりに201 Createdを返し、新しいリソースのURLをレスポンスヘッダーのLocationとして返します。
ismriv 2013

2
@Stephane、リダイレクトはコントローラーのすべてを単純にするだけです。APIの場合でも、作成コントローラーで新しいコンテンツの場所を返し、showコントローラーで新しいコンテンツの表示を処理する方が簡単です。ただし、APIのクライアントの方がコンテンツを取得するだけで、リダイレクトに煩わされない方が便利です。
Alex

45

カバーをリソースとして扱うことは、REST、特にHATEOASの精神に間違いありません。ですから、へのGETリクエストによりhttp://example.com/comic-books/1、カバー1のURIのセットを含むプロパティを含む本1の表現が提供されます。ここまでは順調ですね。

あなたの質問は、コミックブックの作成にどう対処するかです。あなたのビジネスルールが、本が0以上の表紙を持つことであるなら、あなたは問題ありません:

POST http://example.com/comic-books

カバーレスコミックのデータを使用すると、新しいコミックブックが作成され、サーバーが生成したIDが返されます(8に戻るとしましょう)。これで、カバーを次のように追加できます。

POST http://example.com/comic-books/8/covers

エンティティボディにカバーが付いています。

これで、ビジネスルールで常に少なくとも1つのカバーが必要であると記載されている場合にどうなるかという、良い質問があります。いくつかの選択肢がありますが、最初に質問で特定しました。

  1. 最初に表紙の作成を強制します。今度は基本的に非依存リソースを表紙にします。または、漫画本を作成するPOSTのエンティティ本体に最初の表紙を配置します。これは、POSTで作成した表現が、取得した表現とは異なることを意味します。

  2. 主要な、最初の、または好ましい、または別の方法で指定されたカバーの概念を定義します。これはモデリングのハックである可能性が高く、それを行うと、テクノロジーに合わせるためにオブジェクトモデル(概念モデルまたはビジネスモデル)を微調整するようなものになります。素晴らしいアイデアではありません。

カバーレスコミックを単に許可することに対して、これら2つの選択肢を比較検討する必要があります。

あなたは3つの選択肢のうちどれをとるべきですか?あなたの状況についてあまり知りませんが、一般的な1..N依存リソースの質問に答えてください。

  • RESTfulサービスレイヤーに0..Nを使用できる場合は、すばらしいです。おそらく、RESTful SOA間のレイヤーは、少なくとも1つが必要な場合に、さらなるビジネス制約を処理できます。(それがどのように見えるかわかりませんが、調査する価値があるかもしれません...エンドユーザーは通常、とにかくSOAを目にしません。)

  • 1..N制約を単にモデル化する必要がある場合は、カバーが単に共有可能なリソースであるかどうか、つまり、カバーが漫画本以外のものに存在するかどうかを自問してください。これで、それらは依存リソースではなくなりました。最初にそれらを作成し、POSTで漫画本を作成するURIを提供できます。

  • 1..Nが必要でカバーが依存している場合は、本能をリラックスさせてPOSTとGETの表現を同じに保つか、同じにしてください。

最後の項目は次のように説明されています:

<comic-book>
  <name>...</name>
  <edition>...</edition>
  <cover-image>...BASE64...</cover-image>
  <cover-image>...BASE64...</cover-image>
  <cover>...URI...</cover>
  <cover>...URI...</cover>
</comic-book>

POSTするときに、既存のURI(他の本から借用したもの)がある場合は許可しますが、1つ以上の初期画像も含めます。本を作成していて、エンティティに最初のカバー画像がない場合は、409または同様の応答を返します。GETでは、URIを返すことができます。

つまり、基本的にはPOST表現とGET表現が「同じ」であることを許可しますが、GETでカバー画像を「使用」せず、POSTでカバーしないことを選択します。それが理にかなっていると思います。

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