RESTful API設計實踐

1.經過請求類型區分CRUD

方法 操做

場景html

GET
/cars
/cars/711
POST 建立
/cars
PUT 修改
/cars/711
/cars
PATCH 部分修改
/cars/711
DELETE 刪除
/cars/711

 

 

 

 

 

 

 

 

 

2.資源採用名詞,且使用複數

GET /tickets - 獲取 tickets 列表
GET /tickets/12 - 獲取一個單獨的 ticket
POST /tickets - 建立一個新的 ticket
PUT /tickets/12 - 更新 ticket #12
PATCH /tickets/12 - 部分更新 ticket #12
DELETE /tickets/12 - 刪除 ticket #12api

 

3.Get方法和查詢參數不該該涉及狀態改變

不要使用GET 進行狀態改變,瀏覽器

GET /users/711?activate 
GET /users/711/activate

 

4.使用子資源表達關係

若是一個資源與另一個資源有關係,使用子資源:緩存

GET /tickets/12/messages - 獲取ticket #12下的消息列表
GET /tickets/12/messages/5 - 獲取ticket #12下的編號爲5的消息
POST /tickets/12/messages - 爲ticket #12建立一個新消息
PUT /tickets/12/messages/5 - 更新ticket #12下的編號爲5的消息
PATCH /tickets/12/messages/5 - 部分更新ticket #12下的編號爲5的消息
DELETE /tickets/12/messages/5 - 刪除ticket #12下的編號爲5的消息

 

5.使用Http頭聲明序列化格式

在客戶端和服務端,雙方都要知道通信的格式,格式在HTTP-Header中指定服務器

Content-Type 定義請求格式
Accept 定義系列可接受的響應格式restful

 

6.過濾,排序,搜索設計

最好是儘可能保持基本資源URL的簡潔性。 複雜結果過濾器、排序需求和高級搜索 (當限定在單一類型的資源時) ,都可以做爲在基本URL之上的查詢參數來輕鬆實現。下面讓咱們更詳細的看一下:網絡

1)過濾: 對每個字段使用一個惟一查詢參數,就能夠實現過濾。 例如,當經過「/tickets」終端來請求一個票據列表時,你可能想要限定只要那些在售的票。這能夠經過一個像app

GET /tickets?state=open

這樣的請求來實現。這裏「state」是一個實現了過濾功能的查詢參數。負載均衡

 

2)排序: 跟過濾相似, 一個泛型參數排序能夠被用來描述排序的規則. 爲適應複雜排序需求,讓排序參數採起逗號分隔的字段列表的形式,每個字段前均可能有一個負號來表示按降序排序。咱們看幾個例子:搜索引擎

GET /tickets?sort=-priority - 獲取票據列表,按優先級字段降序排序
GET /tickets?sort=-priority,created_at - 獲取票據列表,按「priority」字段降序排序。在一個特定的優先級內,較早的票排在前面

 

3)搜索: 有時基本的過濾不能知足需求,這時你就須要全文檢索的力量。或許你已經在使用 ElasticSearch 或者其它基於 Lucene 的搜索技術。當全文檢索被用做獲取某種特定資源的資源實例的機制時, 它能夠被暴露在API中,做爲資源終端的查詢參數,咱們叫它「q」。搜索類查詢應當被直接交給搜索引擎,而且API的產出物應當具備一樣的格式,以一個普通列表做爲結果。
把這些組合在一塊兒,咱們能夠建立如下一些查詢:

GET /tickets?sort=-updated_at - 獲取最近更新的票
GET /tickets?state=closed&sort=-updated_at - 獲取最近更新而且狀態爲關閉的票。
GET /tickets?q=return&state=open&sort=-priority,created_at - 獲取優先級最高、最早建立的、狀態爲開放的票,而且票上有 'return' 字樣。

 

4)通常查詢定義方式

爲了使普通用戶的API使用體驗更加愉快, 考慮把條件集合包裝進容易訪問的RESTful 路徑中。好比上面的,最近關閉的票的查詢能夠被包裝成 

GET /tickets/recently_closed

5)限制查詢返回字段

API的使用者並不老是須要一個資源的完整表示。選擇返回字段的功能由來已久,它使得API使用者可以最小化網絡阻塞,並加速他們對API的調用。
使用一個字段查詢參數,它包含一個用逗號隔開的字段列表。例如,下列請求得到的信息將剛剛足夠展現一個在售票的有序列表:

GET /tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at

6)Paging分頁

使用 limit 和offset.實現分頁,缺省limit=20 和offset=0;

GET /cars?offset=10&limit=5

爲了將總數發給客戶端,使用訂製的HTTP頭: X-Total-Count.

連接到下一頁或上一頁能夠在HTTP頭的link規定,遵循Link規定:

Link: <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=15&limit=5>; rel="next",
<https://blog.mwaysolutions.com/sample/api/v1/cars?offset=50&limit=3>; rel="last",
<https://blog.mwaysolutions.com/sample/api/v1/cars?offset=0&limit=5>; rel="first",
<https://blog.mwaysolutions.com/sample/api/v1/cars?offset=5&limit=5>; rel="prev",

 

7.更新和建立應該返回一個資源描述

一個 PUT, POST 或者 PATCH 調用可能會對指定資源的某些字段形成更改,而這些字段本不在提供的參數之列 (例如: created_at 或 updated_at 這兩個時間戳)。 爲了防止API使用者爲了獲取更新後的資源而再次調用該API,應當使API把更新(或建立)後的資源做爲response的一部分來返回。

以一個產生建立活動的 POST 操做爲例, 使用一個 HTTP 201 狀態代碼 而後包含一個 Location header 來指向新生資源的URL。

8.只返回JSON

 

9.字段名稱書寫格式統一

選定一種方式:snake_case vs camelCase

 

10.缺省狀況下采用格式化形式和支持gzip

一個提供空白符壓縮輸出的API,從瀏覽器中查看結果並不美觀。雖然一些有序的查詢參數(如 ?pretty=true )能夠提供來使漂亮打印生效,一個默認狀況下能進行漂亮打印的API更爲平易近人。額外數據傳輸的成本是微不足道的,尤爲是當你比較不執行gzip壓縮的成本。
考慮一些用例:假設分析一個API消費者正在調試而且有本身的代碼來打印出從API收到的數據——默認狀況下這應是可讀的。或者,若是消費者抓住他們的代碼生成的URL,並直接從瀏覽器訪問它——默認狀況下這應是可讀的。這些都是小事情。作好小事情會使一個API能被更愉快地使用

 

11.錯誤設計

就像一個HTML錯誤頁面給訪問者展現了有用的錯誤信息同樣,一個API應當以一種已知的可以使用的格式來提供有用的錯誤信息。 錯誤的表示形式應當和其它任何資源沒有區別,只是有一套本身的字段。
API應當老是返回有意義的HTTP狀態代碼。API錯誤一般被分紅兩種類型: 表明客戶端問題的400系列狀態碼和表明服務器問題的500系列狀態碼。最簡狀況下,API應當把便於使用的JSON格式做爲400系列錯誤的標準化表示。若是可能(意思是,若是負載均衡和反向代理能建立自定義的錯誤實體), 這也適用於500系列錯誤代碼。
一個JSON格式的錯誤信息體應當爲開發者提供幾樣東西 - 一個有用的錯誤信息,一個惟一的錯誤代碼 (可以用來在文檔中查詢詳細的錯誤信息) 和可能的詳細描述。這樣一個JSON格式的輸出可能會像下面這樣:

{
"code" : 1234,
"message" : "Something bad happened :(",
"description" : "More details about the error here"
}

對PUT, PATCH和POST請求進行錯誤驗證將須要一個字段分解。下面多是最好的模式:使用一個固定的頂層錯誤代碼來驗證錯誤,並在額外的字段中提供詳細錯誤信息,就像這樣:

{
"code" : 1024,
"message" : "Validation Failed",
"errors" : [
 {
    "code" : 5432,
    "field" : "first_name",
    "message" : "First name cannot have fancy characters"
},
{
    "code" : 5622,
    "field" : "password",
    "message" : "Password cannot be blank"
}
]
}

 

12.HTTP狀態碼

HTTP定義了一套能夠從API返回的有意義的狀態代碼。 這些代碼可以用來幫助API使用者對不一樣的響應作出相應處理。我已經把你必然會用到的那些列成了一個簡短的清單:

  • 200 OK (成功) - 對一次成功的GET, PUT, PATCH 或 DELETE的響應。也可以用於一次未產生建立活動的POST
  • 201 Created (已建立) - 對一次致使建立活動的POST的響應。 同時結合使用一個位置頭信息指向新資源的位置- Response to a POST that results in a creation. Should be combined with a Location header pointing to the location of the new resource
  • 204 No Content (沒有內容) - 對一次沒有返回主體信息(像一次DELETE請求)的請求的響應
  • 304 Not Modified (未修改) - 當使用HTTP緩存頭信息時使用304
  • 400 Bad Request (錯誤的請求) - 請求是畸形的, 好比沒法解析請求體
  • 401 Unauthorized (未受權) - 當沒有提供或提供了無效認證細節時。若是從瀏覽器使用API,也能夠用來觸發彈出一次認證請求
  • 403 Forbidden (禁止訪問) - 當認證成功可是認證用戶無權訪問該資源時
  • 404 Not Found (未找到) - 當一個不存在的資源被請求時
  • 405 Method Not Allowed (方法被禁止) - 當一個對認證用戶禁止的HTTP方法被請求時
  • 410 Gone (已刪除) - 表示資源在終端再也不可用。當訪問老版本API時,做爲一個通用響應頗有用
  • 415 Unsupported Media Type (不支持的媒體類型) - 若是請求中包含了不正確的內容類型
  • 422 Unprocessable Entity (沒法處理的實體) - 出現驗證錯誤時使用
  • 429 Too Many Requests (請求過多) - 當請求因爲訪問速率限制而被拒絕時

 

 ----------------------------------------------------------------------

參考資料:
一、《Best Practices for Designing a Pragmatic RESTful API
二、《RESTful API 設計最佳實踐》(對上文的譯文)
三、《Principles of good RESTful API Design

相關文章
相關標籤/搜索