RESTful 是目前最流行的 API 設計規範,用於 Web 數據接口的設計nginx
爲了不歧義,文檔大量使用了「能願動詞」,對應的解釋以下:json
必須 (MUST)
:絕對,嚴格遵循,請照作,無條件遵照;必定不可 (MUST NOT)
:禁令,嚴令禁止;應該 (SHOULD)
:強烈建議這樣作,可是不強求;不應 (SHOULD NOT)
:強烈不建議這樣作,可是不強求;能夠 (MAY)
和 可選 (OPTIONAL)
:選擇性高一點,在這個文檔內,此詞語使用較少;API 的根入口點應儘量保持足夠簡單,這裏有兩個常見的 URL 根例子:api
https://api.example.com/* https://example.com/api/*
若是你的應用很龐大或者你預計它將會變的很龐大,那 應該
將 API 放到子域下(api.example.com)。這種作法能夠保持某些規模化上的靈活性。bash
API 返回的數據格式,不該該
是純文本,而應該
是一個 JSON
對象,由於這樣才能返回標準的結構化數據。因此,客戶端但願服務器迴應的 HTTP 頭的Content-Type屬性要設爲application/json。服務器
GET /users/2 HTTP/1.1 Accept: application/json Content-Type: application/json
全部的 API 必須保持向後兼容,你 必須
在引入新版本 API 的同時確保舊版本 API 仍然可用。因此 應該
爲其提供版本支持。restful
目前比較常見的兩種版本號形式:app
在 URL 中嵌入版本編號debug
https://api.example.com/v1/* https://api.example.com/v2/*
將版本號放在 HTTP Header 頭中 經過媒體類型來指定版本信息設計
Accept: application/vnd.example.com.v1+json
HTTP 請求動詞一般就是五種方法,對應 CRUD 操做。代理
針對每個端點來講,下面列出全部可行的 HTTP
動詞和端點的組合
請求方法 | URL | 描述 |
---|---|---|
GET | /zoos | 列出全部的動物園(ID和名稱,不要太詳細) |
POST | /zoos | 新增一個新的動物園 |
GET | /zoos/{zoo} | 獲取指定動物園詳情 |
PUT | /zoos/{zoo} | 更新指定動物園(整個對象) |
PATCH | /zoos/{zoo} | 更新動物園(部分對象) |
DELETE | /zoos/{zoo} | 刪除指定動物園 |
GET | /zoos/{zoo}/animals | 檢索指定動物園下的動物列表(ID和名稱,不要太詳細) |
GET | /animals | 列出全部動物(ID和名稱)。 |
POST | /animals | 新增新的動物 |
GET | /animals/{animal} | 獲取指定的動物詳情 |
PUT | /animals/{animal} | 更新指定的動物(整個對象) |
PATCH | /animals/{animal} | 更新指定的動物(部分對象) |
GET | /animal_types | 獲取全部動物類型(ID和名稱,不要太詳細) |
GET | /animal_types/{type} | 獲取指定的動物類型詳情 |
GET | /employees | 檢索整個僱員列表 |
GET | /employees/{employee} | 檢索指定特定的員工 |
GET | /zoos/{zoo}/employees | 檢索在這個動物園工做的僱員的名單(身份證和姓名) |
POST | /employees | 新增指定新員工 |
POST | /zoos/{zoo}/employees | 在特定的動物園僱傭一名員工 |
DELETE | /zoos/{zoo}/employees/{employee} | 從某個動物園解僱一名員工 |
超出Restful
端點的,應該
模仿上表的方式來定義端點。
若是記錄數量不少,服務器不可能都將它們返回給用戶。API
應該
提供參數,過濾返回結果。下面是一些常見的參數。
全部 URL
參數 必須
是全小寫,必須
使用下劃線類型的參數形式。
分頁參數必須
固定爲page
、per_page
常用的、複雜的查詢 應該
標籤化,下降維護成本。如
GET /trades?status=closed&sort=sortby=name&order=asc
對建立新資源的 POST 操做進行響應。應該帶着指向新資源地址的 Location 頭
服務器接受了請求,可是還未處理,響應中應該包含相應的指示信息,告訴客戶端該去哪裏查詢關於本次請求的信息
對不會返回響應體的成功請求進行響應(好比 DELETE 請求)
請求異常,好比請求中的body沒法解析
沒有進行認證或者認證非法或失效
服務器已經理解請求,可是拒絕執行它
該狀態碼錶示用戶請求的資源不存在,如
都 必須
返回該狀態碼,若該資源已永久不存在,則 應該
返回 410
響應。
所請求的 HTTP 方法不容許當前認證用戶訪問
該狀態碼錶示由於請求存在衝突沒法處理。
如經過手機號碼提供註冊功能的 API,當用戶提交的手機號已存在時,必須 返回此狀態碼。
表示當前請求的資源已永久不存在。當調用老版本 API 的時候頗有用
該狀態碼錶示服務器拒絕處理當前請求,由於該請求提交的實體數據大小超過了服務器願意或者可以處理的範圍。
此種狀況下,服務器能夠關閉鏈接以避免客戶端繼續發送此請求。
若是這個情況是臨時的,服務器 應該
返回一個 Retry-After
的響應頭,以告知客戶端能夠在多少時間之後從新嘗試。
該狀態碼錶示請求的 URI
長度超過了服務器可以解釋的長度,所以服務器拒絕對該請求提供服務。
一般表示服務器不支持客戶端請求首部 Content-Type
指定的數據格式。如在只接受 JSON
格式的 API
中放入 XML
類型的數據並向服務器發送,都 應該
返回該狀態碼。
該狀態碼也可用於如:只容許上傳圖片格式的文件,可是客戶端提交媒體文件非法或不是圖片類型,這時 應該
返回該狀態碼:
HTTP/1.1 415 Unsupported Media Type Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 12:09:40 GMT Connection: keep-alive {"error_code":41500,"message":"不容許上傳的圖片格式"}
用來表示校驗錯誤
{ "message": "422 Unprocessable Entity", "errors": { "name": [ "姓名 必須爲字符串。" ] }, "status_code": 422 }
該狀態碼錶示用戶請求次數超過容許範圍。如 API
設定爲 60次/分鐘
,當用戶在一分鐘內請求次數超過 60 次後,都 應該
返回該狀態碼。而且也 應該
在響應首部中加上下列頭部:
X-RateLimit-Limit: 10 請求速率(由應用設定,其單位通常爲小時/分鐘等,這裏是 10次/5分鐘) X-RateLimit-Remaining: 0 當前剩餘的請求數量 X-RateLimit-Reset: 1529839462 重置時間 Retry-After: 120 下一次訪問應該等待的時間(秒)
列子
必須
爲全部的 API 設置 Rate Limit 支持。
服務器遇到了一個不曾預料的情況,致使了它沒法完成對請求的處理。通常來講,這個問題都會在服務器端的源代碼出現錯誤時出現。
服務器不支持當前請求所須要的某個功能。當服務器沒法識別請求的方法,而且沒法支持其對任何資源的請求。
做爲網關或者代理工做的服務器嘗試執行請求時,從上游服務器接收到無效的響應。
因爲臨時的服務器維護或者過載,服務器當前沒法處理請求。這個情況是臨時的,而且將在一段時間之後恢復。若是可以預計延遲時間,那麼響應中能夠包含一個 Retry-After 頭用以標明這個延遲時間。若是沒有給出這個 Retry-After 信息,那麼客戶端應當以處理500響應的方式處理它。
注意:503狀態碼的存在並不意味着服務器在過載的時候必須使用它。某些服務器只不過是但願拒絕客戶端的鏈接。
做爲網關或者代理工做的服務器嘗試執行請求時,未能及時從上游服務器(URI標識出的服務器,例如HTTP、FTP、LDAP)或者輔助服務器(例如DNS)收到響應。
注意:某些代理服務器在DNS查詢超時時會返回400或者500錯誤
對於錯誤數據,默認使用以下結構:
'message' => ':message', // 錯誤的具體描述 'errors' => ':errors', // 參數的具體錯誤描述,422 等狀態提供 'code' => ':code', // 業務自定義的異常碼 'status_code' => ':status_code', // http狀態碼 'debug' => ':debug', // debug 信息,非生產環境提供
HTTP/1.1 422 Unprocessable Entity Content-Type: application/json { "message": "422 Unprocessable Entity", "errors": { "username": [ "姓名 必須爲字符串。" "姓名 必須介於 4 - 18 個字符之間" ], "phone": [ "手機號碼 格式不正確。" ] }, "status_code": 422 }
HTTP/1.1 403 Forbidden Content-Type: application/json { "message": "您無權訪問該訂單", "status_code":"403" }
HTTP/1.1 429 Too Many Requests Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked X-RateLimit-Limit: 10 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1529839462 Retry-After: 290 Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 11:19:32 GMT Connection: keep-alive { "message":"You have exceeded your rate limit.", "status_code":429 }
{ "data": [ { "id": 1, "name": "Eladio Schroeder Sr.", "email": "therese28@example.com", }, { "id": 2, "name": "Liliana Mayert", "email": "evandervort@example.com", } ], "links":{ "first": "http://example.com/pagination?page=1", "last": "http://example.com/pagination?page=1", "prev": null, "next": null }, "meta":{ "current_page": 1, "from": 1, "last_page": 1, "path": "http://example.com/pagination", "per_page": 15, "to": 10, "total": 10 } }