2016-10-13 138 views
6

我正在設計一個RESTful API,並提出了與子資源相關的問題。RESTful API - 設計子資源

我看到其他API使用完整的URL來操作子資源。以Company has DepartmentsDepartment has Employees爲例。

在開始時我會討論實現所有可能的URL。從而在以下方面:

解決方法A

01. ### COMPANY URLS ### 
02. DELETE /companies/{companyId} 
03. GET /companies/{companyId} 
04. POST /companies 
05. PUT /companies/{companyId} 
06. 
07. ### DEPARTMENT URLS ### 
08. DELETE /companies/{companyId}/departments/{departmentId} 
09. GET /companies/{companyId}/departments/{departmentId} 
10. POST /companies/{companyId}/departments 
11. PUT /companies/{companyId}/departments/{departmentId} 
12. DELETE /departments/{departmentId} 
13. GET /departments/{departmentId} 
14. PUT /departments/{departmentId} 
15. 
16. ### EMPLOYEE URLS ### 
17. DELETE /companies/{companyId}/departments/{departmentId}/employees/{employeeId} 
18. GET /companies/{companyId}/departments/{departmentId}/employees/{employeeId} 
19. POST /companies/{companyId}/departments/{departmentId}/employees 
20. PUT /companies/{companyId}/departments/{departmentId}/employees/{employeeId} 
21. DELETE /departments/{departmentId}/employees/{employeeId} 
22. GET /departments/{departmentId}/employees/{employeeId} 
23. POST /departments/{departmentId}/employees 
24. PUT /departments/{departmentId}/employees/{employeeId} 
25. DELETE /employees/{employeeId} 
26. GET /employees/{employeeId} 
27. PUT /employees/{employeeId} 

正如你可以看到,有很多網址,它做同樣的事情。例如:08重複12; 09重複13; 17是重複的21和25 ...

我想刪除重複但保持一致性。所以,重新設計了一個原理爲sup-resources are fine but sub-sub-resources are not的API。這導致在以下方面:

B方法

01. ### COMPANY URLS ### 
02. DELETE /companies/{companyId} 
03. GET /companies/{companyId} 
04. POST /companies 
05. PUT /companies/{companyId} 
06. 
07. ### DEPARTMENT URLS ### 
08. DELETE /departments/{departmentId} 
09. GET /departments/{departmentId} 
10. GET /companies/{companyId}/departments 
11. POST /companies/{companyId}/departments 
12. PUT /departments/{departmentId} 
13. 
14. ### EMPLOYEE URLS ### 
15. DELETE /employees/{employeeId} 
16. GET /employees/{employeeId} 
17. GET /departments/{departmentId}/employees 
18. POST /departments/{departmentId}/employees 
19. PUT /employees/{employeeId} 

我的問題

Q1。是方法B被認爲是RESTful? (我現在假設)

Q2。有沒有陷阱方法B我應該考慮,假設還提供了文檔?

獎勵積分,如果你指向其他API以下方法B

編輯

Elad Tabak呈現良好的見解。

我喜歡一些API使用B方法

https://developers.google.com/youtube/v3/docs/

https://developer.github.com/guides/getting-started/

https://dev.twitter.com/rest/public

+0

這樣做可能有些過於寬泛,Q3和4基本上邀請轉儲書WebService的設計。你應該問一個問題,而不是問卷。你的核心問題似乎是Q1 + Q2的結合。 – Gimby

+0

感謝Gimby,同意,它非常廣泛,我關心Q1和Q2最多。 – Rafa

回答

3

這兩種方法都可以被認爲是基於REST的,只要你不打破羅伊·托馬斯Fielding的論文的chapter 5定義的REST約束:

我看不到常見的陷阱在這兩種方法,但我寧願B方法解決方法A:網址更短,更容易記住,而不是需要很多參數。


加分點:SpotifyFacebook的API採用這種做法。當然還有其他的API,但是這些是我想到的。

+1

其實沒有一個URI本身就是RESTful!它所返回的內容是否符合RESTful約束條件。 REST與乾淨的URI設計無關,而更多的是將客戶端與服務器API分離,因此客戶端應該使用響應返回的URI來對其當前狀態執行進一步的操作。不知道爲什麼每個人都會使用RESTful方法自動將URI設計混淆。除此之外,Fielding還澄清了RESTful API在其[博客文章](http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven)中需要進一步遵守的一些限制條件。 –

3
  1. REST隻字未提URL設計。您提出的任何URL方案都是RESTful。你應該問問它是否是好的設計。是的,第二種方法比第一種更可取。首先是客戶的一大堆噪音,以及業主的巨大維修問題。它也限制了未來的靈活性。

  2. 只要您清楚地記錄如何使用端點,就沒有我意識到的重大缺陷。例如,嵌套端點通常只返回關聯元素,而刪除嵌套元素只會刪除關聯,而不會刪除元素本身。這種行爲需要以某種方式記錄下來。

獎勵要點:要求外部資源超出範圍。

+0

此外,沒有這樣的東西作爲'子資源' – mcintyre321

2

的設計方法提高你需要考慮之間進行選擇時的幾個問題之二:

存在依賴

一個,這是非常直觀的,當你刪除一個公司,你也刪除它的所有子資源 - 部門和員工。 在B中,API用戶需要考慮一下這樣的行爲 - 我是否需要調用所有員工的刪除,還是刪除公司?當然,這可以記錄下來,但仍然不是直截了當的。

A在這裏有一個優勢,因爲它很清楚 - 刪除資源時,刪除所有子資源。

操作端點

另一個問題是它提出了 - 我該如何更新實體?從哪個終點?

如果我想刪除一個員工,是否足以使用一組新員工更新公司?或者我必須刪除該員工?

或者說我想將員工從一家公司更換爲另一家公司。在B,理論上我可以更新員工與公司領域,並完成它。在A有沒有這樣的方式......

A有一個優勢,它非常簡單,如何做一個動作 - 對實體URL的CRUD。 B使API用戶停止並想知道他可以在哪個URL上執行哪個操作。

但是與此同時,B有一個優勢,即更改實體的「父母」(parenting)更容易(如果相關)。

驗證

一個,您必須驗證參數匹配的URL,因爲用戶可以提供員工ID與錯誤的公司或部門。 在B沒有這樣的問題。

1

所以這可能聽起來有點瘋狂,但在HTTP/REST中沒有這樣的'subresource'。

在您的域模型中,沒有公司就不能存在部門。

現在在您的API中,您公開了一個公司的json表示/companies/{companyId}和部門的json表示/companies/{companyId}/departments/{departmentId}

這些都是'資源'。 HTTP/REST術語中的資源只意味着URL指向的內容。所以這是'公司的json代表'而不是公司本身。

URL設計本身就是一個死衚衕 - URL本身可以看起來像任何東西,不管它們是否可讀都沒關係。開發人員提出請求,根據文檔*中的操作名稱選擇URL。嘗試爲URL添加含義本身會很快變得棘手,並且隨着時間的推移實際上可能會增加混淆。

更好地花時間在文檔上,而不是試圖讓人們推斷關於域行爲的事情。

*或超媒體(例如https://github.com/kevinswiber/siren