21

我遇到了一個問題,我無法找到關於在REST風格的Web服務中執行CRUD操作的常用標準或實踐的信息,這些信息的主鍵是其他主鍵資源ID。我們使用MVC WebApi來創建控制器。例如,我們有三個表:複合關鍵資源REST服務

  • Product:PK =產品編號
  • Part:PK = PARTID
  • ProductPartAssoc:PK =(產品編號,PARTID)

的產品可以有許多零件和零件可以是許多產品的組成部分。關聯表還包含與關聯本身相關的其他信息,而不需要進行編輯。

我們有ProductsControllerPartsController類,處理一般的GET/PUT/POST/DELETE使用路由模板操作定義爲:{controller}/{id}/{action}使得下面的IRI的工作:

  • GET,POST /api/Products - 返回所有產品,創建新的產品
  • GET,PUT,DELETE /api/Products/1 - 檢索/更新/刪除產品1
  • GET,POST /api/Parts - 返回各地,創建一個新的部分
  • GET,PUT,DELETE /api/Parts/2 - 檢索/更新/刪除部分2
  • GET /api/Products/1/Parts - 獲取產品1
  • GET /api/Parts/2/Products所有部分 - 得到所有產品的哪個部分2是一個組件

在哪裏我遇到麻煩的是如何爲ProductPartAssoc資源定義路由模板。路線模板和IRI應該如何獲取關聯數據? 秉承慣例,我希望是這樣的:

  • GET,POST /api/ProductPartAssoc - 返回所有協會,創建一個協會
  • GET,PUT,DELETE /api/ProductPartAssoc/[1,2] - 檢索/更新/刪除產品1和部分之間的關​​聯2

我的同事們發現儘管這不美觀,並認爲它會更好,沒有ProductPartAssocController類所有,而是添加其他方法到ProductsController管理協會的數據:

  • GET,PUT,DELETE /api/Products/1/Parts/2 - 獲取數據的產品1和第2部分,而不是數據之間的關聯對於部分2作爲第1部分的成員,這將通常是基於諸如/Book/5/Chapter/3其他實施例的情況我在其他地方見過。
  • POST這裏沒有線索,他們期望IRI看起來像。不幸的是,他們是決策者。

在一天結束時,我想我所尋求的是驗證,或者我可以指出的方向,並且說:「看,這是別人的做法。」

處理由複合鍵標識的資源的典型做法是什麼?

+1

對於鏈接實體,您可以建模您的uri空間,如OData協議爲Odata服務指定的那樣。我並不是建議實施OData服務,但它值得關注,因爲它提供了有用的見解,並且更接近您的問題。在這裏尋找管理實體之間的鏈接:http://www.odata。org/documentation/odata-v2-documentation/operations /#29_Manipulating_Links – 2013-04-23 23:21:01

+0

ProductPartAssoc的外觀如何?而且,它支持哪些CRUD操作? – 2013-04-24 01:55:04

+0

該示例是任意的,但ProductPartAssoc類可能看起來像(對於簡潔性 - 這裏是有限的空間感到抱歉):class ProductPartAssoc {int ProductId; int PartId; int amountUsed;十進制assemblyCost; int installerId; }並需要支持所有四個CRUD操作 - 創建,檢索,更新,刪除。 – Mitselplik 2013-04-24 15:17:32

回答

17

我也喜歡/api/Products/1/Parts/2的美學。您也可以使用多個路由進行相同的操作,因此您可以將它翻倍,並且還提供/api/Parts/2/Products/1作爲同一資源的替代網址。

至於POST,你已經知道了複合鍵。那麼爲什麼不消除對POST的需求,並且僅僅使用PUT來創建和更新呢?如果您的系統生成主鍵,那麼POST到集合資源URL非常好,但是如果您有已知主鍵的組合,爲什麼需要POST?

也就是說,我也喜歡單獨使用ProductPartAssocController來包含這些URL的操作。你將不得不做一個自定義的路由映射,但如果你使用的東西很容易做,就像AttributeRouting.NET

例如,我們這樣做對角色的管理用戶:

PUT, GET, DELETE /api/users/1/roles/2 
PUT, GET, DELETE /api/roles/2/users/1 

6 URL的,但只有3個動作,都在GrantsController(我們稱之爲用戶和角色「許可」之間的動名詞)。班結束了尋找這樣的事情,使用AttributeRouting.NET

[RoutePrefix("api")] 
[Authorize(Roles = RoleName.RoleGrantors)] 
public class GrantsController : ApiController 
{ 
    [PUT("users/{userId}/roles/{roleId}", ActionPrecedence = 1)] 
    [PUT("roles/{roleId}/users/{userId}", ActionPrecedence = 2)] 
    public HttpResponseMessage PutInRole(int userId, int roleId) 
    { 
     ... 
    } 

    [DELETE("users/{userId}/roles/{roleId}", ActionPrecedence = 1)] 
    [DELETE("roles/{roleId}/users/{userId}", ActionPrecedence = 2)] 
    public HttpResponseMessage DeleteFromRole(int userId, int roleId) 
    { 
     ... 
    } 

    ...etc 
} 

這似乎是一個相當直觀的方法給我。將這些操作保存在一個單獨的控制器中也可以使精簡控制器成爲可能

+1

感謝您的洞察力:-)有兩件事:(1)感謝AttributeRouting.Net的提示 - 真棒的東西。 (2)回想起來,你是對的,不需要POST操作。感謝您指出了這一點。我將你的答案標記爲回答我的問題...... – Mitselplik 2013-04-26 14:45:18

0

我建議:

  • POST /api/PartsProductsAssoc:創建零件和產品之間的聯繫。在POST數據中包含零件和產品ID。
  • GET,PUT,DELETE /api/PartsProductsAssoc/<assoc_id>:讀取/更新/刪除鏈接<assoc_id>(不是零件或產品ID,是的,這意味着在您的PartsProductsAssoc表中創建一個新列)。
  • GET /api/PartsProductsAssoc/Parts/<part_id>/Products:獲取與給定零件關聯的產品列表。
  • GET /api/PartsProductsAssoc/Products/<product_id>/Parts:獲取與給定產品相關的零件清單。

理由採取這種做法:

  • 單,完全合格的URI的每一個環節。
  • 修改鏈接會修改單個REST資源。

欲瞭解更多信息,請參閱https://www.youtube.com/watch?v=hdSrT4yjS1g於56:30。