2012-01-29 132 views
22

想象一下,一個網絡應用程序存儲一些數據資源,這些數據資源有一些id,每個數據存儲三個附件(例如pdf)。多個資源的RESTful原子更新?

的URL方案是

data/{id}/attachment1 
data/{id}/attachment2 
data/{id}/attachment3 

的REST風格的API存在提供GET/PUT附件/ DELETE在服務器端執行CRUD操作操作。

又讓ID是123,想以執行其中

  • 附件1由一個新的附件替換一個操作(使得GET file/123/attachment1返回一個新的附件)
  • attachment2被刪除(使得即GET file/123/attachment2返回404)
  • attachment3保持不變。

更新應該是原子 - 完整的更新是由服務器執行或根本沒有。

應用簡單的PUT file/123/attachment1DELETE file/123/attachment2不是原子的,因爲在PUT之後客戶端可能會崩潰,並且服務器沒有提示他應該在這種情況下進行回滾。

那麼如何以RESTful的方式實現操作?

我想過兩種解決方案,但他們似乎都沒有100%的RESTful:

  • 使用Patch(可放,但PATCH能更好地反映的 的部分更新的語義)與多/表格數據/ 123:多部分/表格數據是由與字段「attachment1」和 相關聯的新的 「application/pdf」組成的實體序列,其將代表空值以表示空值刪除 附件2。

雖然這確保了原子性,但我懷疑這是RESTful,因爲我使用不同的參數列表來重載PATCH方法,這違反了統一接口約束。

  • 使用表示事務的資源。我可以將數據ID 123 發佈到事務URL,該事務URL將創建表示服務器上存儲的數據資源 的當前狀態的副本的事務資源 ,例如,交易/數據/ 123。現在我可以調用PUT和 DELETE這個臨時資源的附件(例如DELETE transaction/data/123/attachment2)並且通過 transaction/data/123將此版本的資源提交到服務器的服務器通信 。這確保了原子性,同時必須實現額外的服務器端邏輯來處理多個客戶端 更改相同的資源和崩潰的客戶端永遠不會提交。

雖然這似乎與REST一致,但似乎違反了無國籍的限制。事務資源的狀態不是服務狀態,而是應用程序狀態,因爲每個事務資源都與單個客戶端相關聯。

我有點卡在這裏,所以任何想法會有所幫助,謝謝!

+2

第二種方法的好處是提供了一個很好的數據更改歷史記錄,並可能允許您跳過某些日誌記錄。 – Jasper 2012-04-06 07:07:37

+0

@mtsz我現在正在努力解決這個問題。我喜歡下面選擇的答案,但創建短暫的臨時生命週期的交易資源似乎有很多工作要做。你認爲給原子事務執行一個像「switcheroo」這樣的名稱並創建一個執行該事務的特定Web服務會很糟糕嗎?例如,具有{fileId:123}的主體的POST/doSwitcheroo ....該服務將具有邏輯地以文件形式執行上面在ID爲123的文件中描述的動作012 – 2015-11-11 02:22:57

回答

15

您想使用第二個選項,即交易選項。

什麼你缺少的是交易的創建:

POST /transaction 

HTTP/1.1 301 Moved Permanently 
Location: /transaction/1234 

現在你有一個交易的資源,是一個一流的公民。您可以添加,刪除,查詢當前內容,最後提交或刪除(即回滾)事務。

交易正在進行中時,它只是另一種資源。這裏沒有客戶狀態。任何人都可以添加到此事務中。

當全部完成後,服務器將使用一些超出範圍的內部事務機制一次性應用更改。

您可以在事務子動作中捕獲諸如Etags和if-modified標頭之類的東西,這樣當它們全部應用時,就會知道背後沒有變化。

+0

聽起來很合理。在這種情況下,「申請狀態」的概念可能有點過分誇大了,而這個「頭等公民」是正常的服務狀態。 [Richardson&Ruby](http://shop.oreilly.com/product/9780596529260.do)宣傳這種解決方案,雖然它應用於多服務器場景。我想知道,Roy Fielding會做什麼? :) – mtsz 2012-04-09 18:22:43

+6

您可以像查看購物車一樣查看交易。在購物車中,客戶隨着時間的推移建立他們的交易,然後他們只需完成結賬過程,最終以他們「確認」或「取消」訂單結束。當你用這些術語來看它時,用這個詞彙來說,它更有意義。但在10000英尺時,它們基本上是同樣的問題。 「這是我想要做的所有事情的清單 - 現在,去!」購物車綁定到特定用戶的事實是安全/身份問題,而不是「狀態」與「無狀態」問題。 – 2012-04-09 18:30:56

+0

我已經實現了這個很好的解決方案。您可以獲得解決「編輯比賽」的好處,而不會免費丟失數據,這是「列表」解決方案無法實現的。 – mtsz 2012-04-19 18:35:01

5

非常有趣的問題。在盧加諾(瑞士)大學的計算機學教授寫了一篇關於這種情況的一些幻燈片:

http://www.slideshare.net/cesare.pautasso/atomic-transactions-for-the-rest-of-us

但是我真的不知道,他提供的解決方案是完全基於REST的,因爲它似乎並沒有真正上無國籍服務器端。

說實話,由於交易本身是由多個國家組成,我不認爲這個問題可以有一個完全RESTful解決方案。

+1

我瀏覽了他們的論文(朝向RESTful上的分佈式原子事務服務)。他們提出一個帶有協調器資源的Try-Cancel/Confirm協議,最終確認所有參與資源的變化(或啓動先前狀態的恢復)。資源是分佈式服務器,因此範圍稍大於我的範圍。儘管如此,這個TCC協議應該與上面提到的第二種解決方案非常相似。至少他們在概念上解決應用程序狀態問題,將其轉換爲服務狀態,通過附加方式恢復以前的狀態。也許就是這樣。 – mtsz 2012-01-30 03:27:16

0

假設你的URI是分層:您的問題

PUT data/{id} 
[attachment2,attachment3] 

部分原因是,附件1/2/3是一種可怕的標識符。索引不應該是你的URI的一部分。

+0

標識符是任意的,可以使場景更通用。設想一個具體的場景,其中有數據blob,並附帶預期的模型,描述,圖片等。由於PUT是連續的,我不明白您的解決方案如何解決多個連接資源的一致性更新問題? – mtsz 2012-04-06 12:56:17

+0

將附件列表視爲資源。你正在推銷內容和訂單。 1操作。 – noah 2012-04-06 13:37:39

+0

因此,如果我理解正確,您可以選擇使用建模順序的媒體類型,如multipart/form-data或自定義類型。由於我的原始問題包含此解決方案,因此閱讀該解決方案的合理性會很有趣。 – mtsz 2012-04-09 18:01:22

0

我沒有經驗,但我有一個解決方案的想法,因爲我正面臨開發中的這個問題。

首先,我使用我(客戶端)在一個房子(有資源的服務器)向Fred1發送消息的類比,我希望他關閉電燈開關(更改資源部分的狀態)並打開水壺(改變資源的另一部分的狀態)。不幸的是,在關掉電燈開關後,Fred發生心臟病。

現在我已經從弗雷德沒有得到任何迴應,說他是否做我所問。 Fred被另一個Fred取代。我發送的消息沒有收到答覆。我可以繼續的唯一方法是問Fred2電燈開關是否關閉,電水壺是否打開(在我要求他爲我做東西之後,資源處於我期望的狀態)。這是一個不幸的事態(錯誤),並增加了我的工作量,但我現在可以繼續,因爲我知道Fred1在心臟病發作之前做了什麼。我可以回到繪圖板(通知用戶出現了問題,我們需要重新執行該操作),或者做出可以完成我的請求(如果仍然相關)的更改(打開水壺)。

這是我如何做的開始,顯然有關於範圍,但如果我已經定義了我的範圍(我只對電燈開關和水壺感興趣),那麼我應該有足夠的信息(知道燈開關和電水壺的狀態)給Fred2一個新的命令,而不需要回到用戶的指令。

這聽起來怎麼樣?

+0

有趣但有問題:當Fred關閉燈光後發生心臟病時,您的狀態會不一致。只要你使用你的客戶檢查狀態併發送另一個消息給下一個Fred(他希望不會死),它就會不一致。如果你的客戶在fred死後剛剛死亡會發生什麼?那麼預期的狀態將永遠消失。其他客戶將面臨目前的不一致的狀態,這可能會導致嚴重的麻煩... – mtsz 2012-04-19 18:32:27

+0

確實有趣:)數據庫怎麼樣 - 他們怎麼做?一個數據庫必須是內部原子的,所以也許這是另一個看起來不錯的地方。我正在運行PostgreSQL,因此會檢查文檔。這是PostgreSQL原子的鏈接:http://www.postgresql.org/files/developer/transactions.pdf – tentimes 2012-04-20 11:09:48

+0

您可以採用數據庫會話的概念(例如sql會話):您在會話中應用的所有修改都是沒有執行,直到你提交你的會話。當其中一項修改發生錯誤時,會話將回滾並保留前一個一致狀態。所以當Fred在燈開關打開後死亡時,他拋出一個被捕獲的HeartFailureException,觸發一次會話回滾,並且燈再次亮起;) – mtsz 2012-04-23 15:37:00