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友好,能夠靈活支援,并可以适用于任何作業系統。