簡體   English   中英

RESTful API和批量操作

[英]RESTful API and bulk operations

我有一個中間層,它在共享數據庫上執行CRUD操作。 當我將產品轉換為.NET Core時,我認為我也會考慮使用REST作為API,因為CRUD應該是它的功能。 似乎REST對於單個記錄操作來說是一個很好的解決方案,但是當我想要刪除1000條記錄時會發生什么?

每個專業的多用戶應用程序都會有一些樂觀並發檢查的概念:如果沒有一些反饋,你就不能讓一個用戶消除另一個用戶的工作。 據我了解,REST使用HTTP ETag頭記錄處理此問題。 如果客戶端發送的ETag與服務器的標記不匹配,則發出412 Precondition Failed 到現在為止還挺好。 但是,當我想刪除1,000條記錄時,我會使用什么? 1,000次單獨調用的來回時間是相當可觀的,那么REST如何處理涉及Optimistic Concurrency的批處理操作?

REST的重點是資源和客戶端與服務器的分離,但它不是簡單的CRUD架構或協議。 雖然CRUD和REST看起來非常相似,但通過REST原則管理資源通常也會產生副作用 因此,將REST描述為簡單的CRUD是過於簡單化。

關於REST資源的批處理,底層協議(通常是HTTP)確實定義了可以使用的功能。 HTTP定義了一些可用於修改多個資源的操作。

POST是該協議的通用瑞士軍刀,可以用來根據您的喜好來管理資源。 由於開發人員定義了語義,您可以使用它來一次創建,更新或刪除多個資源。

PUT具有用請求的有效負載主體替換在給定URI處可獲得的資源的狀態的語義。 如果將PUT請求發送到“list”-resource並且有效負載定義了條目列表,則也可以實現批處理操作。

POST和PUT方法之間的根本區別在於封閉表示的不同意圖。 POST請求中的目標資源旨在根據資源自身的語義處理封閉的表示,而PUT請求中的封閉表示被定義為替換目標資源的狀態。

...

應用於目標資源的PUT請求可能對其他資源產生副作用。 例如,文章可能具有用於標識“當前版本”(資源)的URI,該URI與標識每個特定版本的URI(在一個點上共享與當前版本資源相同的狀態的不同資源)分開。 因此,對“當前版本”URI的成功PUT請求可能除了改變目標資源的狀態之外還創建新版本資源,並且還可能導致在相關資源之間添加鏈接。 來源

PATCHRFC 5789 )尚未包含在HTTP協議中,盡管有很多框架支持。 它主要用於一次更改多個資源或對資源執行部分更新,如果更新的部分是某個其他資源的子資源, PUT也能夠實現; 在這種情況下,它具有對外部資源進行部分更新的效果。

重要的是要知道PATCH請求包含服務器必須執行的必要步驟以將資源轉換為其預期狀態。 因此,客戶必須抓住當前狀態並預先計算轉換所需的必要步驟。 關於這個主題的一篇非常翔實的博客文章是“ 不要像傻瓜一樣修補” 這里JSON PatchRFC )是一種基於JSON的媒體類型,可以清晰地顯示PATCH概念。 必須完全應用補丁請求(補丁請求中定義的每個操作)或根本不應用補丁請求。 因此,在任何操作失敗的情況下,它需要事務范圍處理和回滾。

ETagIfModifiedSinceIfModifiedSince條件請求在RFC 7232中定義,並且只有在請求應用於最新版本的資源時才能在HTTP請求中用於執行修改,因此與(分布式)數據庫中的樂觀鎖定相關。

到現在為止還挺好。 但是,當我想刪除1,000條記錄時,我會使用什么?

這取決於您將使用的框架。 如果它支持PATCH我清楚地投票給PATCH 如果它沒有,你可能比PUT更安全使用POST ,因為PUT具有非常嚴格的語義,因為語義是由你明確定義的。 在批量刪除的情況下,也可以通過使用空體來定位集合資源來使用PUT ,該空體具有移除集合中的任何項目並因此清除整個集合的結果。 如果某些項目仍應保留在集合中,則PATCHPOST可能更容易使用。

如果我理解正確,您需要單獨為每條記錄提供樂觀並發。 也就是說,只有當狀態符合客戶的期望時,才會刪除每條記錄。 (如果你只想斷言整個集合的狀態,那么If-Match和412就足夠了。)

Roman Vottner的回答在解釋所涉及的HTTP方法方面做得非常出色,但我會嘗試填寫一些細節。

買者自負

當我們談論“REST將如何處理”這個或那個時,您就會明白,從技術上講,您可以以任何適合您的方式使用HTTP作為傳輸。

因此,當您詢問REST時,我假設您對統一接口感興趣 - 這種方法理論上可以被各種客戶端和服務器使用。

但關鍵詞是“理論上”。 例如,一旦你定義了自己的媒體類型(你自己的JSON結構),很多一致性就會消耗殆盡,因為無論如何客戶端都必須針對你的特定API進行編碼,此時你可以要求它跳轉通過你想要的任何籃球。

但如果你仍然有興趣盡可能多地挽救一致性,那么請繼續閱讀。

全有或全無

如果你想要一個全有或全無的操作,如果任何一個單獨的前置條件失敗,它將完全失敗,那么,正如Roman建議的那樣,你可以使用PATCHJSON Patch格式。 為此,您需要將集合的概念表示形式作為要應用修補程序的單個JSON對象。

例如,假設您有/my/collection/1/my/collection/4等資源。 您可以將/my/collection/為:

{
    "resources": {
        "1": {
            "href": "1",
            "etag": "\"BRkDVtYw\"",
            "name": "Foo Bar",
            "price": 1234.5,
            ...
        },
        "4": {
            "href": "4",
            "etag": "\"RCi8knuN\"",
            "name": "Baz Qux",
            "price": 2345.6,
            ...
        },
        ...
    }
}

這里, "1""4"是相對於/my/collection/ URL。 您可以使用特定於域的ID,但正確的REST根據不透明URL進行操作。

標准不要求您在GET /my/collection/上實際提供此表示,但如果您確實支持此類請求,則應使用該表示。 無論如何,對於此結構,您可以應用以下JSON補丁:

PATCH /my/collection/ HTTP/1.1
Content-Type: application/json-patch+json

[
    {"op": "test", "path": "/resources/1/etag", "value": "\"BRkDVtYw\""},
    {"op": "remove", "path": "/resources/1"},
    {"op": "test", "path": "/resources/4/etag", "value": "\"RCi8knuN\""},
    {"op": "remove", "path": "/resources/4"},
    ...
]

這里, path不是URL路徑,它是進入上述表示的JSON指針

如果所有修補程序操作都成功,那么您將使用成功的狀態代碼(如204(無內容)200(確定))進行響應。

如果任何ETag test操作失敗,則以409(沖突)響應。 在這種情況下,您不應該回復412(Precondition Failed) ,因為請求本身沒有前提條件(如If-Match )。

如果出現其他任何問題,您可以使用其他適當的狀態代碼進行響應:請參閱RFC5789§2.2RFC7231§6.6

混合的結果

如果你不想要“全有或全無”的語義,那么我不知道任何標准化的解決方案。 正如Roman所說,在這種情況下你不能使用PATCH方法,但你可以使用自定義媒體類型的POST( RFC6838§3.4 )。 它可能看起來像這樣:

POST /my/collection/ HTTP/1.1
Content-Type: application/x.my-patch+json
Accept: application/x.my-patch-results+json

{
    "delete": [
        {"href": "1", "if-match": "\"BRkDVtYw\""},
        {"href": "4", "if-match": "\"RCi8knuN\""},
        ...
    ]
}

無論是否有任何刪除成功,您都可以使用200(OK)響應此類請求。 另一種選擇是207(多狀態) ,但在這種情況下我沒有看到任何好處,並且它沒有在WebDAV之外廣泛使用,因此Postel的定律建議不要去那里。

HTTP/1.1 200 OK
Content-Type: application/x.my-patch-results+json

{
    "delete": [
        {"href": "1", "success": true},
        {"href": "4", "success": false, "error": {...}},
        ...
    ]
}

當然,如果補丁首先無效,則應該適當地使用415(不支持的媒體類型)422(不可處理的實體)進行響應。

另一個角度

1000個人通話的來回時間相當可觀

它在HTTP / 1.1中。 但是,如果您可以使用HTTP / 2(它對並發請求有更好的支持,以及每個請求的小得多的網絡開銷),那么1000個單獨的請求可能會很好地為您服務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM