2008-09-29 65 views
124

我想知道如何在REST中實現以下用例。在不影響概念模型的情況下甚至可以做到這一點?REST中的交易?

在單個事務的範圍內讀取或更新多個資源。例如,從Bob的銀行賬戶轉賬100美元到John的賬戶。

據我所知,唯一的方法來實施這是通過作弊。您可以發佈到與John或Bob關聯的資源,並使用單個事務執行整個操作。就我而言,這打破了REST體系結構,因爲您基本上是通過POST隧道傳輸RPC調用,而不是真正在單個資源上運行。

回答

79

考慮一個RESTful購物籃場景。購物籃概念上是您的交易封套。同樣,您可以將多個項目添加到購物籃中,然後提交該購物籃來處理訂單,您可以將Bob的帳戶條目添加到交易包裝,然後將Bill的帳戶條目添加到包裝。當所有的部分到位時,你可以POST/PUT事務包裝器的所有組件。

+0

我得到購物籃示例,但是當你將它推廣時,它根本聽起來不是RESTful(你不是在資源上運行)。沒有現實的銀行相關資源來包裝John和Bob。 雖然很好的答案!我覺得你一定會朝着正確的方向前進。 – Gili 2008-09-29 02:46:42

+15

爲什麼TransferMoneyTransaction不是一個可行的銀行資源? – 2008-09-29 02:58:49

9

你必須推出自己的「交易ID」類型的TX管理。因此,這將是4個電話:

http://service/transaction (some sort of tx request) 
http://service/bankaccount/bob (give tx id) 
http://service/bankaccount/john (give tx id) 
http://service/transaction (request to commit) 

你不得不處理在DB的操作的存儲(如負載平衡),或在內存或這樣,那麼處理提交,回滾,超時。

在公園裏並不是真正的RESTful日子。

+4

我不認爲這是一個特別好的例子。您只需要兩個步驟:創建事務(在「掛起」狀態下創建事務)和提交事務(如果未提交則提交,並將資源移至提交或回滾狀態)。 – 2011-01-19 22:36:53

-3

我想你可以包括譚的URL /資源:

  1. PUT /交易來獲取ID(例如 「1」)
  2. [PUT,GET,POST,無論]/1 /帳戶/鮑勃
  3. [PUT,GET,POST,無論]/1 /帳戶/票據
  4. DELETE /交易ID爲1

只是一個想法。

+0

我看到這種方法的兩個問題: 1)它意味着你不能訪問交易之外的資源(儘管這可能不是什麼大問題)。 2)迄今爲止的答案都沒有涉及服務器不再是無狀態的事實,儘管我懷疑沒有辦法做到這一點。 – Gili 2008-09-29 02:08:39

+0

那麼/ 1/account/bob和/ account/bob只是兩個不同的資源。 :)和RE:無狀態,它意味着資源總是可用的,不依賴於先前的請求。既然你要求交易,是的,情況並非如此。但是,再次,你想要交易。 – Till 2008-09-29 09:06:39

+1

如果客戶端必須組裝URI,那麼您的API不是RESTful。 – aehlke 2009-07-22 20:27:59

2

我認爲在這種情況下打破REST的純理論是完全可以接受的。在任何情況下,我都不認爲REST中實際上有任何內容說你不能在需要它的商業案例中觸及依賴對象。

我真的認爲,如果您可以利用數據庫來完成這項工作,那麼您將不必花費額外的時間來創建自定義事務管理器。

0

在簡單情況下(沒有分佈式資源),您可以將事務視爲資源,創建它的行爲達到最終目標。

因此,要在<url-base>/account/a<url-base>/account/b之間轉換,您可以將以下內容發佈到<url-base>/transfer

 
<transfer> 
    <from><url-base>/account/a</from> 
    <to><url-base>/account/b</to> 
    <amount>50</amount> 
</transfer> 

這將創建一個新的傳輸資源,並返回傳輸的新的URL - 例如<url-base>/transfer/256

在成功發佈時,「真實」交易在服務器上執行,金額從一個帳戶中刪除並添加到另一個帳戶。

但是,這並不包括分佈式交易(如果說'一個'在一個銀行背後是一個服務,而'b'在另一個銀行背後是另一個服務) - 除了說「嘗試以不需要分佈式事務的方式來描述所有操作「。

50

但是也有一些不被這個問題,我認爲這是太糟糕了回答了幾個重要的情況下,因爲它有:-)

在谷歌高排名的搜索字詞具體來說,一個漂亮的propertly會是:如果您POST兩次(因爲一些緩存在中間打嗝)你不應該兩次轉移金額。

爲了達到此目的,您創建一個事務作爲對象。這可能包含您已知的所有數據,並使事務處於未決狀態。

POST /transfer/txn 
{"source":"john's account", "destination":"bob's account", "amount":10} 

{"id":"/transfer/txn/12345", "state":"pending", "source":...} 

一旦你有了這個交易,就可以提交它,是這樣的:

PUT /transfer/txn/12345 
{"id":"/transfer/txn/12345", "state":"committed", ...} 

{"id":"/transfer/txn/12345", "state":"committed", ...} 

注意,多放不在這一點無關緊要;即使是txn上的GET也會返回當前狀態。具體來說,第二個PUT會檢測到第一個已經處於適當的狀態,並且只是將其返回 - 或者,如果在已經處於「已提交」狀態之後嘗試將其置於「回滾」狀態,則會得到錯誤,以及實際提交的事務回來。

只要您與單個數據庫或具有集成事務監視器的數據庫交談,此機制實際上可以正常工作。您可能還會爲交易引入暫停,如果您願意,您甚至可以使用Expires標題表示暫停。

28

在REST術語中,資源是可以通過CRUD(創建/讀取/更新/刪除)動詞來處理的名詞。由於沒有「轉賬款」動詞,我們需要定義一個可以通過CRUD來處理的「交易」資源。這是HTTP + POX中的一個例子。第一步是CREATE(HTTP POST方法)的新事務:

POST /transaction 

這將返回一個交易ID,例如「1234」並根據URL「/ transaction/1234」。請注意,多次觸發此POST不會創建具有多個ID的同一個事務,並且還會避免引入「pending」狀態。另外,POST不能總是冪等的(REST要求),所以通常將POST中的數據最小化是一種很好的做法。

您可以將交易ID的生成保留給客戶端。在這種情況下,您將POST/transaction/1234創建事務「1234」,如果服務器已經存在,服務器將返回錯誤。在錯誤響應中,服務器可以使用適當的URL返回當前未使用的ID。使用GET方法向服務器查詢新ID不是一個好主意,因爲GET決不應該改變服務器狀態,並且創建/保留新ID會改變服務器狀態。

接下來,我們UPDATE(PUT HTTP方法)的所有數據的事務,隱含提交它:

PUT /transaction/1234 
<transaction> 
    <from>/account/john</from> 
    <to>/account/bob</to> 
    <amount>100</amount> 
</transaction> 

如果ID爲 「1234」 之前已經PUT事務時,服務器對的錯誤響應,否則爲OK響應和URL來查看已完成的事務。

注意:在/ account/john中,「john」應該是John的唯一帳號。

17

偉大的問題,REST主要是解釋類似數據庫的例子,其中存儲,更新,檢索,刪除的東西。像這樣的例子很少,服務器應該以某種方式處理數據。我不認爲羅伊·菲爾丁在他的論文中包含任何內容,畢竟這是基於http。

但是他確實談到了「代表性狀態轉移」作爲一個狀態機,其中鏈接轉移到下一個狀態。通過這種方式,文檔(表示)跟蹤客戶端狀態,而不是服務器必須執行的操作。通過這種方式,沒有客戶端狀態,只顯示您所在的鏈接。

我一直在想這個,在我看來合理的是讓服務器爲你處理一些東西,當你上傳時,服務器會自動創建相關資源,並給你鏈接(在事實上,它不需要自動創建它們:它只能告訴你鏈接,並且只有當你遵循它們時才創建它們 - 懶惰創建)。並給你鏈接創建新的相關資源 - 相關資源具有相同的URI但更長(添加後綴)。例如:

  1. 您上傳(POST )一交易的所有信息的概念的代表性。這看起來就像一個RPC調用,但它確實創建了「建議的事務資源」。例如URI:/transaction 毛刺會導致創建多個這樣的資源,每個資源都有不同的URI。
  2. 服務器的響應說明了創建的資源的URI及其表示 - 這包括鏈接(URI)以創建新的「提交事務資源」的相關資源其他相關資源是刪除建議交易的鏈接。這些是狀態機中的狀態,客戶可以遵循這些狀態。從邏輯上講,這些是服務器上創建的資源的一部分,超出了客戶端提供的信息。 e.g的URI:/transaction/1234/proposed/transaction/1234/committed
  3. POST的鏈接打造「提交的事務資源」,這將創建一個資源,改變服務器的狀態(這兩個賬戶的餘額)**。就其性質而言,該資源只能創建一次,並且無法更新。因此,承諾多次交易的故障不會發生。
  4. 您可以獲取這兩個資源,查看它們的狀態。假設POST可以更改其他資源,則該提議現在將被標記爲「已提交」(或者根本不可用)。

這與網頁的操作方式類似,最終網頁上會顯示「你確定要這麼做?」最終的網頁本身就是交易狀態的表示,其中包括進入下一個狀態的鏈接。不只是金融交易;也可以(例如)預覽,然後提交維基百科。我猜REST的區別在於狀態序列中的每個階段都有一個明確的名稱(它的URI)。

在實際交易/銷售中,交易的不同階段(提案,採購訂單,收據等)通常會有不同的實物憑證。更多用於購買房屋,以及結算等。

OTOH這種感覺就像玩弄語義給我;我對將動詞轉化爲名詞使其成爲RESTful的名詞化感到不安,「因爲它使用名詞(URI)而不是動詞(RPC調用)」。即名詞「提交事務資源」而不是動詞「提交此事務」。我認爲名義化的一個優點是你可以通過名稱來引用資源,而不需要以某種其他方式指定它(例如維護會話狀態,所以你知道這個「事務」是什麼......)

但重要的問題是:這種方法有什麼好處?即,這種REST風格比RPC風格更好的方式是什麼?是一種對網頁有用的技術,除了存儲/檢索/更新/刪除之外,還有助於處理信息?我認爲REST的主要優勢是可擴展性;其中一個方面是不需要明確維護客戶端狀態(但使其隱含在資源的URI中,而下一個狀態作爲其表示中的鏈接)。從這個意義上說它有幫助。也許這有助於分層/流水線呢? OTOH只有一個用戶會查看他們的具體事務,所以緩存它並沒有什麼好處,所以其他人可以閱讀它,這是http的大勝。

1

您不能在REST中使用服務器端事務。

其中一個REST約束上的:

無國籍

的客戶機 - 服務器通信是通過無客戶端上下文進一步限制被存儲請求之間的服務器上。來自任何客戶端的每個請求都包含爲請求提供服務所需的所有信息,並且任何會話狀態都保存在客戶端中。

唯一的RESTful方法是創建一個事務重做日誌並將其放入客戶端狀態。與請求的客戶端發送的重做日誌和服務器重新進行交易和

  1. 輥事務回,但提供了一個新的事務重做日誌(一步)
  2. 或最終完成交易。

但是,也許使用支持服務器端事務的基於服務器會話的技術會更簡單。

10

如果您回過頭來總結這裏的討論,很明顯REST並不適用於許多API,特別是當客戶端 - 服務器交互本身具有狀態性時,與非平凡事務一樣。爲什麼要跳過所有的建議,爲了客戶端和服務器端,爲了迂迴地遵循一些不適合問題的原則?更好的原則是爲客戶提供最簡單,最自然,最有效的方式來與應用程序合成。總之,如果你真的在應用程序中做了很多事務(類型,而不是實例),那麼你實際上不應該創建一個RESTful API。

1

我相信會使用客戶端上生成的唯一標識符來確保連接打嗝不會隱含API保存的雙重性。

我認爲使用客戶端生成的GUID字段以及傳輸對象,並確保不重新插入相同的GUID將是銀行轉賬問題的更簡單的解決方案。

不知道更復雜的情況,如多個機票預訂或微架構。

我找到了一篇關於這個主題的論文,關於dealing with the transaction atomicity in RESTful services的經驗。

5

我已經從這個話題漸行漸遠了10年。回想起來,我無法相信這個宗教冒充科學,當你谷歌休息+可靠的時候,你會進入這個科學領域。混亂是神話。

我會分裂這個廣泛的問題分爲三個:

  • 下游服務。您開發的任何Web服務都將使用您使用的下游服務,並且您的交易語法只能遵循。您應該嘗試隱藏服務用戶的所有內容,並確保您的操作的所有部分成功或失敗,然後將此結果返回給用戶。
  • 您服務。客戶希望網絡服務調用能夠獲得明確的結果,而通常在實質性資源上直接發佈POST,PUT或DELETE請求的REST模式讓我覺得這種提供這種確定性的方法很糟糕,而且很容易改進。如果你關心可靠性,你需要確定行動請求。這個ID可以是在客戶端上創建的GUID,也可以是服務器上關係數據庫的種子值,這並不重要。對於服務器生成的ID,請求 - 響應專用於交換ID。如果這個請求失敗或一半成功,沒有問題,客戶端只是重複請求。未使用的ID不會造成傷害。

    這很重要,因爲它可以讓所有後續請求完全冪等,因爲如果它們重複n次,它們將返回相同的結果並且不會導致任何進一步的結果。服務器存儲所有針對操作ID的響應,如果它看到相同的請求,它會重播相同的響應。對模式的更全面的處理在this google doc。文檔提出了一個實現,我相信(!)廣泛地遵循REST原則。專家肯定會告訴我它是如何違反他人的。無論是否存在下游事務,這種模式都可以用於任何不安全的Web服務調用。
  • 將您的服務整合到由上游服務控制的「交易」中。在網絡服務的情況下,完整的ACID交易通常被認爲是不值得的,但通過在確認響應中提供取消和/或確認鏈接,您可以極大地幫助消費者服務,從而實現transactions by compensation

您的要求是一個基本要求。不要讓人們告訴你,你的解決方案不是猶太教。根據他們解決問題的方式和方式,來判斷他們的架構。