2009-09-09 28 views
7

一個RESTful,hypertext-driven系統需要使客戶能夠創建一個新的資源,這個資源依賴於三個或更多不同類型的資源。公開此功能的最佳方法是什麼?REST:如何創建一個資源取決於三種或更多不同類型的資源?

舉一個例子,假設我運行在線商店。該服務器可以識別四種資源:

  • 訂單:要運集團的產品。 [有一個貨件]
  • 目的地:要運送到的位置。 [有很多貨件]
  • 裝運:將產品發送給客戶的行爲。 [屬於目的地,訂單和打包者]
  • 包裝員:員工在物理上準備裝運訂單。 [有很多貨件]

訂單發貨時,客戶需要通過在服務器上創建一個新貨件來記錄此事件。該貨件需要參考目的地,訂單和打包機。

要實現新的出貨量創造,我能想到的三種方法,而且我不喜歡任何人:

  1. POST使用裝運媒體類型/出貨。貨運媒體類型有三個字段:「order_uri」; 「packer_uri」;和「destination_uri」。每個URI分別用作裝運中涉及的訂單,打包機和目的地的唯一標識符。
  2. 使用貨運媒體類型發佈到/ orders/{order_id}/packers/{packer_id}/destinations/{destination_id} /貨件。
  3. 向系統中添加一個名爲「ShipmentBuilder」的新資源。使用ShipmentBuilder媒體類型中包含的「packer_uri」,「destination_uri」和「order_uri」POST到/ shipment_builders。

我不喜歡選項1,因爲Shipment媒體類型另外定義了指令,打包器和目標的鏈接。這裏,「鏈接」是由人類可讀名稱,URI和媒體類型組成的JSON哈希。將「order_uri」,「packer_uri」和「destination_uri」添加到媒體類型看起來不太乾燥,因爲它複製了關聯資源的URI。

選項2使用深層嵌套的URI,既不看起來很維護也不捕獲任何有意義的分層信息。

選項3在客戶端和創建貨件之間提供了另一個抽象層次,這使得系統難以學習。

如果貨件只依賴於另一個資源,則選項2會更有意義,但在這種情況下它不適用。就目前而言,我贊成選項3,但更喜歡更好的東西。

在這個例子中,創建新貨件的URI和媒體類型的最佳組合是什麼?還應考慮哪些其他方法?

更新:以下是貨件資源的JSON示例表示,顯示訂單,包裝員和目的地的鏈接。在「出貨」散列通過選項1出現所需的URI複製:

{ 
    "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」字段中)將得到公佈。使用GET時,上面的完整貨件表示將被髮送。

+0

您能否詳細說明爲什麼您覺得向發貨媒體類型添加URI似乎不是DRY?我不明白你指的是什麼重複。 –

+0

Darrel,在底部添加了一些東西。 –

回答

2

REST「層次結構」不要意味着任何東西。它們以導航的方式顯示路徑形式的關係。不是等級本身,而是一個路徑。因此,如果放棄「層次結構」概念並認識到有相同的最終位置有很多替代路徑,則選項2實際上是明智的。

您的選項2是一個orders-> packers-> destination路徑。從理論上講,訂單 - > destinations->加殼和packers->訂單 - >目的地,packers-> destinations->訂單,以及其他一些人都導致同一個地方。是的,支持他們都是一種痛苦。然而,這證明了他們都是等價沒有層次。

「我不喜歡選項1,因爲[它]看起來不太乾燥。」

所以呢?拋棄重複的東西。爲什麼一個貨件還必須包含訂單和包裝員信息的完整重複? URI引用足以允許查找和檢索Order和Packer。爲什麼要發送Order和Packer?

「選項3使系統更難學習。」爲了誰?開發商?你正在圍繞開發人員設計你的系統,而不是用戶和他們的用例?恥辱。

REST的要點是(通常)URI是一個絕對的,最終的和永恆的東西。哪種替代方法爲您提供絕對最佳的URI結構?認識到URI的是層次結構,但路徑 - 和對象可在多個備選路徑到底存在。

你正在創建一個裝運。 POST到/shipment。簡單,明確的URI是重要的。

+0

爲什麼你認爲「REST的意義在於(通常)URI是一個絕對的,最終的和永恆的東西」?我的理解是,超媒體的原因之一是能夠允許服務器更改Url而不會中斷客戶端。這不就是爲什麼HTTP有301響應代碼。 當然「酷網址不會改變」,但有時我們在定義我們的虛擬路徑時會犯錯誤。 –

+0

我喜歡你的URI描述爲不是層次結構的路徑。這是看待事物的完全不同的方式。當用戶點擊「主頁」鏈接時,隱喻並不完全適用。 –

+0

@Daniel Miller:很酷的URI不能改變或者一切都會中斷。一個301是一個真正的錯誤,一個設計良好的網站不會這樣做(除了作爲一個以瀏覽器爲中心的「重定向後」的黑客)。你可以把「家」想象成你想要的任何東西;但不要讓它混淆你的RESTful URI設計。 –

1

好了,現在我明白了,你所看到的重複。發佈以下內容是否可行?

{ 
    "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", 
    } 
    } 
} 

,並返回該

{ 
    "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" 
    } 
    } 
} 

也許這只是沒有在JSON的工作,但我在我的資源XML類似的東西。這個想法是,你可以傳遞給服務器一個「參考」的資源,只需填入uri,服務器就會填充對象中的其餘數據。

+0

看起來服務器添加的部分是Links「order」,「packer」和「destination」的「name」和「media_type」字段,對吧?如果是這樣,這個解決方案將刪除重複的URI引用。在上面,鏈接包含在「出貨」屬性散列中,而在原始媒體類型定義中,鏈接在屬性散列外部。不過,它可以工作。 –

+0

這種方法引入了一點複雜性,因爲客戶需要知道,不允許設置「訂單」,「打包商」和「目的地」鏈接的「media_type」或「name」屬性(創建錯誤?) - 只能設置每個鏈接的「uri」屬性。 –

+0

是的你是對的。我更喜歡XML的原因之一是我可以在特定情況下使用屬性和元素之間的區別來區分數據和元數據。元數據屬性可以幫助客戶知道什麼可以和什麼不能改變。 –

0

我認爲option1和option2是公平的解決方案,我會忘記option3,因爲以前的解決方案是更好的解決方案。

您的客戶端應該總是通過檢查鏈接的語義(例如鏈接關係和供應商特定的MIME類型)而不是通過檢查URL結構來決定。您不一定需要特定於供應商的MIME類型,您可以使用RDF格式,例如JSON-LD和REST以及特定於應用程序的詞彙來描述您的鏈接及其輸入字段,您可以使用例如Hydra。您也可以使用自定義解決方案,例如將_fields添加到_links。

重複的鏈接沒有錯。如果郵件大小太大,可以使用gzip。順便說一句,你不應該混淆URL和鏈接,它們是不同的東西。 URL是資源標識符,鏈接是資源上可能的操作調用。

相關問題