2009-09-09 4 views
7

RESTful、hypertext-drivenシステムでは、クライアントが異なるタイプの3つ以上のリソースに依存する新しいリソースを作成できるようにする必要があります。この機能を公開する最良の方法は何ですか?REST:異なる種類の3つ以上のリソースに依存するリソースを作成する方法

たとえば、オンラインストアを実行しているとします。サーバーは約4つのリソースを知っています。

  • 注文:出荷する製品のグループ。 [1つの貨物を持っています]
  • 宛先:出荷先です。 [多くの貨物を持っている]
  • 貨物:製品を顧客に送る行為。 [宛先、注文、およびパッカーに属します]
  • パッカー:従業員が物理的に出荷の注文を準備しています。 [多くの貨物があります]

注文が出荷されると、クライアントはサーバーに新しい貨物を作成してこのイベントを記録する必要があります。出荷には、Destination、Order、およびPackerへの参照が必要です。

は、私は3つのアプローチを考えることができ、新たな出荷の作成を実現するために、私はそれらのいずれかを好きではない:出荷メディアタイプを使用して/出荷に

  1. POSTを。出荷メディアタイプには3つのフィールドがあります: "order_uri"; "packer_uri";と "destination_uri"。各URIは、出荷に関係する注文、パッカー、および宛先の一意の識別子としてそれぞれ使用されています。
  2. 出荷メディアタイプを使用して、/ orders/{order_id}/packers/{packer_id}/destination/{destination_id}/shipmentにPOSTします。
  3. "ShipmentBuilder"という名前のシステムに新しいリソースを追加します。 ShipmentBuilderメディアタイプに含まれている "packer_uri"、 "destination_uri"、 "order_uri"を使用して/ shipipment_buildersにPOSTします。

私はオプション1が嫌いです。なぜなら、出荷メディアタイプは、注文、包装業者、および行き先へのリンクを追加定義するからです。ここで、「リンク」は、人間が読める名前、URI、およびメディアタイプからなるJSONハッシュです。メディアタイプに「order_uri」、「packer_uri」、および「destination_uri」を追加することは、関連付けられたリソースのURIを複製するため、あまりDRYに見えません。

オプション2は、深くネストされたURIを使用します。深くネストされたURIは、非常に保守的に見えず、意味のある階層情報も取得しません。

オプション3では、クライアントと出荷の作成の間に別のレベルの抽象化があり、システムの学習が困難になります。

出荷が他のリソースにのみ依存する場合、オプション2はもっと意味がありますが、この場合はありません。それが現れて、私はオプション3を好むが、より良いものを好むだろう。

この例では、新しい貨物を作成するためのURIとメディアタイプの最適な組み合わせは何ですか?考慮すべき他のアプローチは何か?

アップデート:以下は、注文、パッカー、および宛先のリンクを示す出荷リソースのJSONの例です。

{ 
    "shipment":{ 
    "created_at": "Wed Sep 09 18:38:31 -0700 2009", 
    "order_uri":"http://example.com/orders/815", 
    "packer_uri":"http://example.com/packers/42", 
    "destination_uri":"http://example.com/destinations/666" 
    }, 
    "order":{ 
    "name":"the order to which this shipment belongs", 
    "uri":"http://example.com/orders/815", 
    "media_type":"application/vnd.com.example.store.Order+json" 
    }, 
    "packer":{ 
    "name":"the person who packed this shipment", 
    "uri":"http://example.com/packers/42", 
    "media_type":"application/vnd.com.example.store.Packer+json" 
    }, 
    "destination":{ 
    "name":"the destination of this shipment", 
    "uri":"http://example.com/destinations/666", 
    "media_type":"application/vnd.com.example.store.Destination+json" 
    } 
} 

「出荷」のハッシュ(以下「のcreated_at」フィールド)の内容がPOSTさになるだろう:「出荷」のハッシュでオプション1が表示されることにより、必要なURIの重複。 GETを使用している場合、上記の完全な出荷表示が送信されます。

+0

配送メディアタイプへのURIの追加がDRYと思われない理由を詳しく説明できますか?私はあなたが何を参照している重複を理解していない。 –

+0

Darrelは、下部に何かを追加しました。 –

答えて

2

REST "階層"はを意味しません。何でもいいです。それらは、パスの形で関係を示すためのナビゲーションの便宜です。階層はありませんそれ自体はですが、パスです。したがって、オプション2は、「階層」コンセプトを削除し、同じ最終的な場所に多くの代替パスがあることを認識すると、実際には賢明です。

オプション2は、orders-> packers-> destinationのパスです。理論的には、注文 - >目的地 - >パッカーとパッカー - >注文 - >目的地、パッカー - >目的地 - >発注などがすべて同じ場所をリードします。はい、それらをすべてサポートするのは苦痛です。しかし、それはすべてが同等であるという証拠です。階層はありません。

「非常にDRYに見えないのでオプション1が嫌いです。」

だから?反復的なものを残しなさい。なぜ貨物にはOrderとPackerの情報が完全に繰り返されなければならないのですか? URI参照は、検索とOrderとPackerの検索を可能にするのに十分です。なぜOrderとPackerを送信するのですか?

「オプション3を使用すると、システムの学習が困難になります。」誰のため?デベロッパーですか?ユーザーとそのユースケースではなく、開発者の周りにシステムを設計していますか?恥について

RESTのポイントは、URIが絶対的、最終的そして永遠のものであること(一般的に)です。どちらの選択肢があなたに最高のURI構造を与えてくれますか? URIはではなく、の階層であることを認識してください。オブジェクトは複数の代替パスの末尾に存在する可能性があります。

貨物を作成しています。 POST to /shipment。シンプルで明確なURIが重要です。

+0

なぜあなたは「RESTのポイントはURIが絶対的、最終的そして永遠のものであること(一般的に)」と信じていますか?私の理解は、ハイパーメディアの理由の1つは、サーバーがクライアントを壊さずにURLを変更できるようにすることだということです。 HTTPに301のレスポンスコードがある理由もそうではありません。 「Cool Urlsは変更されませんが、確かに仮想パスを定義する際に間違いがあります。 –

+0

URIの記述が階層ではないパスとして好きです。物を見るのとはかなり違う方法です。しかし、ユーザーが「ホーム」リンクをクリックしたときには、このメタファーは保持されません。 –

+0

@Daniel Miller:Cool URIは変更できないか、すべてが破損します。 A 301は本当のエラーであり、うまく設計されたサイトではこれが行われません(ブラウザに焦点を当てた「POST後のリダイレクト」のハッキングを除く)。あなたは "家"をあなたが望むものと考えることができます。 URIのあなたのRESTfulなデザインを混乱させてはいけません。 –

1

ここで、重複が発生している場所をわかりました。次のようにPOSTすることは可能でしょうか?

{ 
    "shipment":{ 
    "created_at": "Wed Sep 09 18:38:31 -0700 2009", 
    "order":{ 
     "uri":"http://example.com/orders/815" 
     }, 
    "packer":{ 
     "uri":"http://example.com/packers/42", 
    } 
    "destination":{ 
     "uri":"http://example.com/destinations/666", 
    } 
    } 
} 

と多分これがちょうどJSONでは動作しませんが、私は私のリソースでXMLと似た何かを、この

{ 
    "shipment":{ 
    "created_at": "Wed Sep 09 18:38:31 -0700 2009", 
    "order":{ 
     "name":"the order to which this shipment belongs", 
     "uri":"http://example.com/orders/815", 
     "media_type":"application/vnd.com.example.store.Order+json" 
    }, 
    "packer":{ 
     "name":"the person who packed this shipment", 
     "uri":"http://example.com/packers/42", 
     "media_type":"application/vnd.com.example.store.Packer+json" 
    }, 
    "destination":{ 
     "name":"the destination of this shipment", 
     "uri":"http://example.com/destinations/666", 
     "media_type":"application/vnd.com.example.store.Destination+json" 
    } 
    } 
} 

を返します。アイデアは、URIに記入されたリソースへの "参照"をサーバーに渡すことができ、サーバーはオブジェクト内の残りのデータを入力するという考え方です。

+0

サーバーが追加している部分のように、リンク「注文」、「パッカー」、および「宛先」の「名前」フィールドと「メディアタイプ」フィールドが正しく表示されます。もしそうなら、この解決法はURI参照の複製を取り除く。上記では、リンクは「出荷」属性ハッシュ内に含まれていますが、元のメディアタイプ定義では、リンクは属性ハッシュの外部にあります。それでも、それは働くことができます。 –

+0

このアプローチでは、クライアントが "order"、 "packer"、および "destination"リンクの "media_type"属性または "name"属性の設定が許可されていないことを認識する必要があるという点で、エラー?) - 各リンクの "uri"属性だけを設定できます。 –

+0

はい、あなたは正しいです。私がXMLを好む理由の1つは、特定の状況でデータとメタデータを区別するために、属性と要素の区別を使用できることです。メタデータ属性は、クライアントが何ができ、何が変更できないかを知るのに役立ちます。 –

0

私はoption1とoption2は公平な解決策だと思います。前の方が良い解決策であるので、私はoption3を忘れるでしょう。

お客様のクライアントは、URL構造をチェックするのではなく、リンクのセマンティクス(リンク関係やベンダー固有のMIMEタイプなど)を常に確認する必要があります。ベンダー固有のMIMEタイプは必ずしも必要ではなく、JSON-LDやREST、アプリケーション固有のボキャブなどのRDFフォーマットを使用して、リンクや入力フィールドを記述することができます。たとえば、Hydraを使用できます。カスタムソリューションを使用することもできます。たとえば、_fieldsを_linksに追加します。

重複したリンクで何も問題はありません。メッセージサイズが大きすぎる場合、gzipを使用できます。URLをリンクと混同しないでください。別のものです。 URLはリソース識別子であり、リンクはリソース上で可能な操作呼び出しです。

関連する問題