RESTful API設計指南
RESTful API概述
RESTful API是什麼
RESTful是Representational State Transfer的縮寫,代表着表徵狀態轉移。REST擁有一組架構約束條件和原則,只要符合這一套約束原則的架構,就是RESTful架構。
需要注意的是,REST並沒有提供新的組件、技術,也並不是專門爲HTTP提供規範,而是通過約束和原則去合理使用Web的現有特徵和能力(是的,REST受到Web現有特徵的影響還是比較深的)。RESTful API 是一種圍繞 資源(resource)
展開的 無狀態傳輸
的API設計方案。所有的HTTP Action,都應該是在相應resource上可以被操作和處理的,而API 就是對資源的管理操作,而這個具體操作是由 HTTP Action 指定的。
RESTful API在功能上更像是隔離層,要訪問服務器資源,就必須找到API入口。如果這個入口的規則遵循REST風格,那就是RESTful設計框架。
RESTful API產生的意義
近年來隨着移動互聯網的發展,各種類型的Client層出不窮,RESTful可以通過一套統一的接口爲 Web,iOS和Android提供服務。另外對於廣大平臺來說,比如Facebook platform,微博開放平臺,微信公共平臺等,它們不需要有顯式的前端,只需要一套提供服務的接口,於是RESTful更是它們最好的選擇。
規定的資源格式
資源的標識URI
資源的是一個數據單元,這個單元可大可小,根據業務規模自主定製。要準確識別一個資源,需要有一個唯一標識,在Web中這個唯一標識就是URI(Uniform Resource Identifier)。
URI的設計應該具有自釋性,可尋址性,直觀性的原則。用/來表示層級,用_或-來分割單詞,用?來過濾資源。
比較常見的URI:
HTTP協議語義支持
- GET:從服務器取出資源或資源列表
- POST:在服務器新建一個資源
- PUT:客戶端提供數據,以整體的方式更新服務器資源
- PATCH:只更新服務器一個資源的一個屬性
- DELETE:從服務器刪除資源
- HEAD:從服務器獲取報頭信息(不是資源)
- OPTIONS:獲取客戶端能對資源做什麼操作的信息
除了POST不是冪等的,其他幾個都是冪等的。
HTTP的冪等性是指一次和多次請求某一個資源應該具有同樣的副作用。冪等性的一個實例:在網速不夠快的條件下,客戶端發送第一個請求後不能立即得到響應,由於不能確定是否請求是否被成功提交,所以它有可能會再次發送另一個相同的請求,冪等性決定了第二個請求是否有效。冪等情況下,第一次請求成功實現了事務操作,第二次請求就一定不能再次操作事務。
媒體類型
客戶端與服務端進行交互式,需要規定雙方能夠接受的媒體表現形式。常見的媒體格式類型有:
- application/json:JSON數據格式
- application/xhtml+xml:XHTML數據格式
- application/xml:XML數據格式
- application/atom+xml:ATOM XML聚合格式
在設計RESTful API的時候,要規定端端之間具有統一的數據傳輸格式,目前JSON數據格式使用範圍比較廣。
好的API是什麼樣的
大家都知道,API表達的是數據和數據使用者之間契約的說明。打破這樣一種契約會造成客戶端數據沒辦法正確獲取,文檔的效果也大打折扣。
那一個好的API是要應該做到可擴展的。隨着業務和服務的開張,這樣的API要成長爲一個公共平臺的契約說明。爲了做到廣義適配,需要有一定的規範,從而讓廣大的用戶輕鬆地消費這個平臺的數據。API也容易使用,第三方調用者在使用上更爲方便,用戶調用這個API來消費平臺數據,這個平臺的數據也更爲有價值。
關於Version版本化
https://developer.github.com/v3/git/tags/
版本化信息可以放在URI中,也可以放在請求頭裏面(Github選擇前一種方案)
無論你正在構建什麼,無論你在入手前做了多少計劃,你核心的應用總會發生變化,數據關係也會變化,資源上的屬性也會被增加或刪除。只要你的項目還活着,並且有大量的用戶在用,這種情況總是會發生。
請謹記一點,API是服務器與客戶端之間的一個公共契約。如果你對服務器上的API做了一個更改,並且這些更改無法向後兼容,那麼你就打破了這個契約,客戶端又會要求你重新支持它。爲了避免這樣的事情,你既要確保應用程序逐步的演變,又要讓客戶端滿意。那麼你必須在引入新版本API的同時保持舊版本API仍然可用。
注:如果你只是簡單的增加一個新的特性到API上,如資源上的一個新屬性或者增加一個新的端點,你不需要增加API的版本。因爲這些並不會造成向後兼容性的問題,你只需要修改文檔即可。
隨着時間的推移,你可能聲明不再支持某些舊版本的API。申明不支持一個特性並不意味着關閉或者破壞它。而是告訴客戶端舊版本的API將在某個特定的時間被刪除,並且建議他們使用新版本的API。
一個好的RESTful API會在URL中包含版本信息。另一種比較常見的方案是在請求頭裏面保持版本信息。但是跟很多不同的第三方開發者一起工作後,我可以很明確的告訴你,在請求頭裏麪包含版本信息遠沒有放在URL裏面來的容易。
根URL
以https://developer.github.com/v3/git/tags/爲例,其根URL是https://developer.github.com/v3/
這裏可能大家會有疑惑,前面提到的是URI,後面怎麼說的是URL,其實這裏有一些包含與被包含的關係,用一張圖來說明。
添加過濾
大數據包的傳輸過程中容易丟包,針對這種情況,可以讓客戶端自己對結果做一些具體的過濾或限制,這麼做最重要的一個原因是可以最小化網絡傳輸,並讓客戶端儘可能快的得到查詢結果。其次是客戶端可能比較懶,如果這時服務器能對結果做一些過濾或分頁,對大家都是好事。另外一個不那麼重要的原因是(從客戶端角度來說),對服務器來說響應請求的負載越少越好。
所以只要出現GET的請求,就應該通過URL來過濾信息。以下有一些過濾器可以這麼添加到API中的:
- ?limit=10:減少返回給客戶端的結果數量(用於分頁)
- ?offset=10:發送一堆信息給客戶端(用於分頁)
- ?animal_type_id=1:使用條件匹配來過濾記錄
- ?sortby=name&order=asc:對結果按特定屬性進行排序
狀態碼
HTTP狀態碼是RESTful API很重要的一部分。它是一個HTTP標準,很多的網絡設備都可以識別這些狀態碼,例如負載均衡器可能會在發現某臺web服務器已經發送了很多的50X服務器錯誤之後,避免可能會通過配置避免發送請求到這臺服務器上。
1xx範圍的狀態碼是保留給底層HTTP功能使用的,並且估計在你的職業生涯裏面也用不着手動發送這樣一個狀態碼出來。
2xx範圍的狀態碼是保留給成功消息使用的,你儘可能的確保服務器總髮送這些狀態碼給用戶。
3xx範圍的狀態碼是保留給重定向用的。大多數的API不會太常使用這類狀態碼,但是在新的超媒體樣式的API中會使用更多一些。例如304是指資源未被改動,可以使用客戶端緩存。
4xx範圍的狀態碼是保留給客戶端錯誤用的。例如,客戶端提供了一些錯誤的數據或請求了不存在的內容。這些請求應該是冪等的,不會改變任何服務器的狀態。屬於 客戶端錯誤
5xx範圍的狀態碼是保留給服務器端錯誤用的。這些錯誤常常是從底層的函數拋出來的,並且開發人員也通常沒法處理。發送這類狀態碼的目的是確保客戶端能得到一些響應。收到5xx響應後,客戶端沒辦法知道服務器端的狀態,所以這類狀態碼是要儘可能的避免。屬於 服務端錯誤
認證方式
OAuth2.0提供了一個請求的認證方式。在每一個請求裏,可以明確知道哪個客戶端創建了請求,哪個用戶提交了請求,並且提供了一種標準的訪問過期機制或允許用戶從客戶端註銷,所有這些都不需要第三方的客戶端知道用戶的登陸認證信息。
還有OAuth1.0和xAuth同樣適用這樣的場景。無論你選擇哪個方法,請確保它爲多種不同語言/平臺上的庫提供了一些通用的並且設計良好文檔,因爲用戶可能會使用這些語言和平臺來編寫客戶端。
爲API配上文檔
API沒有文檔,對於第三方開發者來說簡直是非常打擊的一件事。文檔應該遵循以下規則:
- 具有良好的版式。
- 請求和響應的內容應該有完整的東西,並在文檔中使用高亮語法。
- 文檔的每一個端點所預期的響應代碼和可能的錯誤消息和錯誤消息的出現場景說明。
- 可能的話,創建控制檯來讓開發者立即體驗API的功能。(非必要)
- 保證文檔的輸出格式能被打印。
RESTful API實踐
Github的API是RESTful API的一種實踐,可以當作參考來學習。
這裏摘取了Github的幾個uri:
https://github.com/pulls
https://github.com/settings/profile
https://github.com/username?tab=stars
https://developer.github.com/v3/git/tags/
URL
URL中應該儘量使用專屬名詞,避免使用動詞。並將API部署在專用域名之下。
路徑
路徑又稱爲端點(endpoint),表示具體的地址。
在RESTful架構中,每個網址都代表一種資源,所以網址中不能有動詞,只能有名詞,所用的名詞往往和數據庫中的表格名對應。
比如github的pulls和settings的路徑如下:
https://github.com/pulls
https://github.com/settings/profile
找到合適的媒體類型
當需要設計一個API時,可以去找特定領域內的特定設計,這樣就不必要重複設計輪子了。
在數據返回格式方面,大部分的網站優先提供XML、JSON的數據返回,Google定義的GData就是在ATOM基礎上作了擴展,還有一些網站提供了PHP的數據返回。
友好性
友好性主要表現在易擴展,後期需要的功能可以方便添加;
API也應該對上層UI友好,能夠靈活支持,並可以適用於任何操作系統。