2010-01-29 75 views
3

我正試圖找出調用REST操作的最佳方法,這些操作可以從一次調用執行多個操作和多個數據庫更新。在單個REST調用中執行多個數據庫操作

在我的數據模型中,我有Diners和LunchBoxes和Foods。午餐盒只是食客和食物之間的多對多關係,但具有計數屬性,表明給定的晚餐有多少種類型的食物。

我想要建立一個表明晚餐已經吃掉他們的食物之一的調用,這相應地增加了餐廳的健康。某些食物比其他食物更有營養,因此會增加不同量的餐飲者的健康。構成這一行動將是:

  • 減少對晚餐的飯盒計數屬性爲給定的食品通過正確的量
  • 增加晚餐的健康因此

所以兩個表必須這裏更新:晚餐和午餐盒,都在一次交易中。

試圖用名詞,最好我能想出是:

POST /餐廳/坦白/餐

其中描述了一頓XML將類似於

<meal> 
    <food> 
    <id>apple</id> 
    </food> 
    <count>2</count> 
</meal> 

然而,這讓我覺得很有意思。在REST中發佈膳食應該創建膳食資源。在這種情況下,我們不僅創建一個Meal資源,而且還更新其他兩個資源:Diner和LunchBox。

我想一種方法是讓客戶端在兩個不同的調用中處理這個問題 - 一個更新Diner,一個更新LunchBox。但是,這似乎是錯誤的,因爲我們有多個客戶端(HTML,Flash等),都需要執行此操作。如果我們將來更新用於消費食物的業務邏輯,那麼我們需要在許多客戶端上進行更改,而不是在單個服務器上進行更改。

他人如何接近這個公認的非常基本的問題?

回答

1

如果你看一下作爲晚餐,而不是資源本身的作用,這使得更多的意義。不過,我會試圖將名稱改爲動詞,如。在爲REST系統建模時,您做出的一些決策將是任意的。從理論的角度來看,這個動作可以在用餐者LunchBox上。我傾向於按我的應用程序是如何使用模型,所以有什麼用UI適合,什麼是更容易在文檔中解釋給第三方等

沒有什麼在REST模式,決定了底層結構或排除了你在操作中處理相當複雜的事務。在這種情況下,我只需要一個操作,根據需要處理所有使用事務的邏輯。

該行動將對一名餐館進行操作,並列出食物和數量。

在Rails你現在將不得不像

# routes.rb 
map.resources :diner, :member => {:eat => :post} 

#controller 
def eat 
    @diner = Diner.find(params[:id]) 
    @diner.eat(params[:foods]) 
    respond_to ... 
    end 
end 

你會發現,其實我已經推了邏輯到模型中。我假設Diner模型與LunchBox模型有關聯。方法方法將增加健康和改變相關午餐盒中的食物量。這樣你可以非常整齊地封裝所有的邏輯。

UPDATE 我認爲這是一個相當普遍的模式,使資源具有一些​​特定的命名操作。我經常只是將操作添加到我的控制器中,但通過使用HTTP和Rails約定公開這些操作來保持REST的一般框架。

您當然可以將您的系統與Meal建模爲一個資源,但我認爲這會導致您的需求更加複雜。

也可以使用只對進行建模,但是對於真實世界的系統來說,它很笨重笨拙。在這個世界觀中,您開始走下去協調多個http動作的路徑來組成更高階的API。這樣的系統幾乎不可能用一半體面的用戶界面來構建,如果你將API暴露給第三方,他們會討厭你。

+0

謝謝。不過,我在這裏看到了一些我想問的問題。首先,不是「吃」一個令人困惑的選擇,因爲它是一個動詞?這就是爲什麼我想用「餐」的原因,因爲然後你發佈一個新的餐(即關於REST資源的全部名詞是名詞)。其次,由於行動不是冪等的,不應該是POST而不是PUT?最後,這意味着即使用戶不一定要求更新該模型,那麼/餐廳/坦率/吃飯也會有更新LunchBox模型的副作用。在REST下還是猶太教嗎? – mrjake2 2010-01-30 01:11:18

+0

開始發表評論,但是當我用完字符時修改了我的帖子 – 2010-01-30 02:19:50

+0

哦,你說得對vs post,代碼已經修改,我從routes.rb剪切/粘貼我有方便。 – 2010-01-30 02:27:22

1

首先,餐廳和飯盒的更新應該在一個請求中完成。不要陷入嘗試通過REST API執行事務的陷阱。

在我們談到您的具體問題之前,讓我們爲客戶如何與您的服務進行交互以引導您的問題奠定基礎。

客戶端應該始終從根服務url開始。

GET /DiningService 
Content-Type: application/vnd.sample.diningservice+xml 
200 OK 

<DiningService> 
<Link rel="diners" href="./diners"/> 
<Link rel="lunchboxes" href="./lunchboxes"/> 
<Link rel="foods" href="./foods"/> 
</DiningService> 

我不知道你的用戶將與客戶端軟件的交互方式,還是讓我們假設,我們首先需要確定誰是打算做飲食。我們可以通過查看與rel =「diners」鏈接的響應來檢索用戶列表,並按照該鏈接進行查看。

GET /DiningService/diners 
Content-Type: application/vnd.sample.diners+xml 
200 OK 

<Diners> 
<Diner Name="Frank"> 
    <Link rel="lunchbox" href="./Frank/lunchbox"/> 
</Diner> 
<Diner Name="Bob"> 
    <Link rel="lunchbox" href="./Bob/lunchbox"/> 
</Diner> 
</Diners> 

返回的是用餐者列表。爲了簡單起見,我選擇了創建自定義媒體類型,但是對於這些列表,您最好使用Atom提要等。 客戶需要識別弗蘭克作爲餐廳,所以現在我們想要訪問他的飯盒。我們的自定義媒體類型的規則說,弗蘭克的午餐盒 的鏈接可以在帶有rel =「飯盒」的鏈接元素中找到。 我們從響應文檔中獲取該URL並按照它進行操作。

GET /DiningService/Frank/lunchbox 
Content-Type: application/vnd.sample.lunchbox+xml 
200 OK 

<Lunchbox> 
<Link rel="diner" href="/DiningService/Frank"/> 
<Food Name="CheeseSandwich" NutritionPoints="10"> 
      <Link rel="eat" Method="POST" href="/DiningService/Frank?food=/DiningService/Food/CheeseSandwich"/> 
</Food> 
<Food Name="CucumberSandwich" NutritionPoints="15"> 
    <Link rel="eat" Method="POST" href="/DiningService/Frank?food=/DiningService/Food/CucumberSandwich"/> 
</Food> 
</Lunchbox> 

我們得到的回覆是另一種自定義介質類型定義描述我們可以用飯盒做一個飯盒和鏈接的內容。一旦客戶選擇吃飯的食物,我們可以通過尋找與rel =「eat」的鏈接並遵循該URL來識別要跟隨的URL。在這種情況下,這是一個帖子。

POST /DiningService/Frank?food=/DiningService/Food/CucumberSandwich 
Content-Type: None 
200 OK 

我沒想到太難什麼構建url的最好的辦法就是,因爲如果我改變了主意,下週並使其

<Link rel="eat" Method="POST" href="/DiningService/Frank/Mouth?food=/DiningService/Food?id=759"/> 

甚至

​​

這對客戶來說並不重要,因爲它會繼續尋找rel =「eat」的鏈接,並且會跟隨該URL。您可以選擇任何適用於您選擇的Web框架的最簡單的URL結構。 URL結構屬於服務器,您應該可以隨時對其進行更改,並且對客戶端幾乎沒有影響。

如果你採取這種方法,你可以停止強調提出完美的網址。這種「RESTful URL」的虛假概念已經做得更多,以防止人們學習REST而不是SOAP。

+0

謝謝,這個例子幫助我多思考了這個過程。儘管如此,我還是不太瞭解其中的一點 - 如果REST應用程序中的每個項目都應該是一個資源,那麼我不會了解上次調用中所暴露的資源。在電話/ DiningService/Frank?food =/DiningService/Food/CucumberSandwich中,資源是什麼?是弗蘭克嗎,還是CucumberSandwich? – mrjake2 2010-01-30 04:38:49

+0

在那個特定的URL中,資源是Frank。您可能會爭辯說,將食物網址發佈到用餐者資源的含義並不十分清楚。在第二個URL中,我創建了一個名爲「mouth」的特殊「處理資源」,它是餐館的一個子資源,當您向口腔資源發佈食物URL時,會執行吃飯操作。當然,它有點愚蠢,但我的觀點是,只要你正確地使用動詞,那麼url的內容就不重要了。 POST行爲沒有真正定義,所以很難誤用。 – 2010-01-30 05:30:51

相關問題