2013-12-10 56 views
2

讓我們假設我有一個對象,該對象在我的應用程序中作爲REST資源公開。該對象具有許多字段幷包含許多其他對象,包括關聯的集合。像這樣的事情,但想到要大得多:REST資源的動態表示

Customer 
    List<Order> orders 
    List<Address> shippingAddresses; 
    // other fields for name, etc. 

Order 
    List<Product> products 
    // fields for total, tax, shipping, etc. 

Product 
    // fields for name, UPC, description, etc. 

我在API暴露客戶爲/customer/{id}

我的一些客戶將要爲每個訂單的每一件產品的所有細節。如果我遵循HATEOAS,我可以提供鏈接以獲取產品詳細信息。這將導致n + 1呼叫該服務,以在客戶的訂單內填充產品。另一方面,如果我總是填充它,那麼許多客戶端會收到一些他們不需要的信息,我會做大量不需要的數據庫查詢。

如何根據客戶的需求允許我的資源的客戶表示?

我看到幾個選項。

  1. 使用Jackson的JsonView註釋事先指定使用的內容。來電者要求適合他們的觀點。即/customer/{id}?view=withProducts。這需要我在編譯時指定所有可用的視圖,並不會那麼靈活。

  2. 允許呼叫者請求在請求中填充某些字段,即/customer/{id}?fields=orders,firstName,lastName。這將需要我有一些處理程序可以解析f​​ields參數,並可能使用反射來填充東西。聽起來對我來說超級混亂。你對子資源做了什麼。我能做fields=orders.products.upc並以這種方式加入集合嗎?聽起來就像我試圖在REST或其他東西上編寫hibernate一樣。

  3. 按照HATEOAS,並要求客戶端進行百萬次HTTP調用,以填充他們需要的東西。對於那些不想在大多數情況下填充物品的人來說,這種方法非常有效,但對於試圖展示訂單細節總結或其他類似內容的人而言,這會很昂貴。

  4. 具有獨立的資源,爲每個視圖...

  5. 其他?

回答

1

我會做這樣的事情: /客戶/ {ID} /命令/包括=實體

這是一種你選擇1的更具體的變化。

你還能有以下幾種選擇:

  1. 特定的順序從特定客戶沒有產品清單: /客戶/ {ID} /命令/(編號)
  2. 只是訂單沒有產品的客戶: /客戶/ {ID} /命令/

我傾向於避免單一資源,becau大部分時間,或者最終有人總是想要一個事物清單。

+0

根據我的經驗,沒有以下id的'/ customer'會給出這個列表,'/ customer/{id}'是你將它縮小到單個客戶的方式,但這只是一種風格。這是'包含=實體'的東西,這是有趣的部分。這意味着我基本上只有2個選項,一個充分充實,另一個只包含字段。我認爲這幾乎不夠靈活,特別是如果某些相關集合需要昂貴的操作來填充。 – digitaljoel

+0

那麼不是說你是否想包含某個實體,你可以通過說出你想包含哪個實體來解決它。/customers/{id}/orders /?products = yes&productdetails = yes和/ customers/{id}/orders/{id}只會給你一個帶該id的準系統訂單。 –

+0

是啊,那基本上是我的#2。聽起來像沒有這個魔術彈頭。 – digitaljoel

1

選項2(客戶端指定字段)是一種過濾方法,與GETable資源相比,它更像查詢接口。如果您接受POST請求中的部分模板,您的過濾器可能會更具表現力,您的服務將會填充。但這很複雜。

我願意賭你所需要的是任何複雜實體的2個簡單表示。這應該可以處理您域中99.9%的案例。鑑於此,請製作更多的URI,每個URI都用於每個事物的「視圖」。

要處理0.1%的情況(例如,當您需要完全填充Products集合時),請爲允許過濾的嵌套實體提供查詢接口。您甚至可以提供超媒體鏈接來檢索這些集合,作爲上述簡化表示的一部分。

+0

因此,基本上每個視圖都有不同的處理程序。我可以使用JsonView爲我進行序列化,並且可以獲取關聯的集合,而另一個則不會。 – digitaljoel

+0

這是一個很好的方法來做到這一點。認識到這個實體並不是真正的PUTable,因爲它只是一個方便的表示層信息彙編。您在這裏有很大的靈活性,因爲客戶實際上是一個單獨的資源,不知道訂單等。您可能會考慮對此資源使用不同的名稱。 –