該倉庫整理了目前比較流行的 RESTful api
設計規範,爲了方便討論規範帶來的問題及爭議,現把該文檔託管於 Github,歡迎你們補充!!php
Versioninghtml
Response前端
爲了不歧義,文檔大量使用了「能願動詞」,對應的解釋以下:nginx
必須 (MUST)
:絕對,嚴格遵循,請照作,無條件遵照;必定不可 (MUST NOT)
:禁令,嚴令禁止;應該 (SHOULD)
:強烈建議這樣作,可是不強求;不應 (SHOULD NOT)
:強烈不建議這樣作,可是不強求;能夠 (MAY)
和 可選 (OPTIONAL)
:選擇性高一點,在這個文檔內,此詞語使用較少;參見: RFC 2119
客戶端在經過 API
與後端服務通訊的過程當中,應該
使用 HTTPS
協議。git
API
的根入口點應儘量保持足夠簡單,這裏有兩個常見的 URL
根例子:github
若是你的應用很龐大或者你預計它將會變的很龐大,那應該
將API
放到子域下(api.example.com
)。這種作法能夠保持某些規模化上的靈活性。
全部的 API
必須保持向後兼容,你 必須
在引入新版本 API
的同時確保舊版本 API
仍然可用。因此 應該
爲其提供版本支持。json
目前比較常見的兩種版本號形式:後端
api.example.com/v1/*
這種作法是版本號直觀、易於調試;另外一種作法是,將版本號放在 HTTP Header
頭中:api
Accept: application/vnd.example.com.v1+json
其中 vnd
表示 Standards Tree
標準樹類型,有三個不一樣的樹: x
,prs
和 vnd
。你使用的標準樹須要取決於你開發的項目bash
x
)主要表示本地和私有環境prs
)主要表示沒有商業發佈的項目vnd
)主要表示公開發布的項目後面幾個參數依次爲應用名稱(通常爲應用域名)、版本號、指望的返回格式。
至於具體把版本號放在什麼地方,這個問題一直存在很大的爭議,但因爲咱們大多數時間都在使用 Laravel
開發,應該
使用 dingo/api 來快速構建應用,它採用第二種方式來管理 API
版本,而且已集成了標準的 HTTP Response
。
端點就是指向特定資源或資源集合的 URL
。在端點的設計中,你 必須
遵照下列約定:
必須
所有小寫resource
)的命名 必須
是名詞,而且 必須
是複數形式必須
優先使用 Restful
類型的 URL必須
是易讀的必定不可
暴露服務器架構至於 URL 是否必須使用連字符(-
) 或下劃線(_
),不作硬性規定,但必須
根據團隊狀況統一一種風格。
來看一個反例
再來看一個正列
對於資源的具體操做類型,由 HTTP
動詞表示。經常使用的 HTTP
動詞有下面五個(括號裏是對應的 SQL
命令)。
其中
1 刪除資源 必須
用 DELETE
方法
2 建立新的資源 必須
使用 POST
方法
3 更新資源 應該
使用 PUT
方法
4 獲取資源信息 必須
使用 GET
方法
針對每個端點來講,下面列出全部可行的 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 # 可爲其定製快捷方式 GET /trades/recently_closed
應該
使用 OAuth2.0
的方式爲 API 調用者提供登陸認證。必須
先經過登陸接口獲取 Access Token
後再經過該 token
調用須要身份認證的 API
。
Oauth 的端點設計示列
客戶端在得到 access token
的同時 必須
在響應中包含一個名爲 expires_in
的數據,它表示當前得到的 token
會在多少 秒
後失效。
{ "access_token": "token....", "token_type": "Bearer", "expires_in": 3600 }
客戶端在請求須要認證的 API
時,必須
在請求頭 Authorization
中帶上 access_token
。
Authorization: Bearer token...
當超過指定的秒數後,access token
就會過時,再次用過時/或無效的 token
訪問時,服務端 應該
返回 invalid_token
的錯誤或 401
錯誤碼。
HTTP/1.1 401 Unauthorized Content-Type: application/json Cache-Control: no-store Pragma: no-cache { "error": "invalid_token" }
Laravel 開發中,應該
使用 JWT 來爲管理你的 Token,而且必定不可
在api
中間件中開啓請求session
。
全部的 API
響應,必須
遵照 HTTP
設計規範,必須
選擇合適的 HTTP
狀態碼。必定不可
全部接口都返回狀態碼爲 200
的 HTTP
響應,如:
HTTP/1.1 200 ok Content-Type: application/json Server: example.com { "code": 0, "msg": "success", "data": { "username": "username" } }
或
HTTP/1.1 200 ok Content-Type: application/json Server: example.com { "code": -1, "msg": "該活動不存在", }
下表列舉了常見的 HTTP
狀態碼
狀態碼 | 描述 |
---|---|
1xx | 表明請求已被接受,須要繼續處理 |
2xx | 請求已成功,請求所但願的響應頭或數據體將隨此響應返回 |
3xx | 重定向 |
4xx | 客戶端緣由引發的錯誤 |
5xx | 服務端緣由引發的錯誤 |
只有來自客戶端的請求被正確的處理後才能返回2xx
的響應,因此當 API 返回2xx
類型的狀態碼時,前端必須
認定該請求已處理成功。
必須強調的是,全部 API
必定不可
返回 1xx
類型的狀態碼。當 API
發生錯誤時,必須
返回出錯時的詳細信息。目前常見返回錯誤信息的方法有兩種:
一、將錯誤詳細放入 HTTP
響應首部;
X-MYNAME-ERROR-CODE: 4001 X-MYNAME-ERROR-MESSAGE: Bad authentication token X-MYNAME-ERROR-INFO: http://docs.example.com/api/v1/authentication
二、直接放入響應實體中;
HTTP/1.1 401 Unauthorized Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 10:02:59 GMT Connection: keep-alive {"error_code":40100,"message":"Unauthorized"}
考慮到易讀性和客戶端的易處理性,咱們 必須
把錯誤信息直接放到響應實體中,而且錯誤格式 應該
知足以下格式:
{ "message": "您查找的資源不存在", "error_code": 404001 }
其中錯誤碼(error_code
)必須
和 HTTP
狀態碼對應,也方便錯誤碼歸類,如:
HTTP/1.1 429 Too Many Requests Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 10:15:52 GMT Connection: keep-alive {"error_code":429001,"message":"你操做太頻繁了"}
HTTP/1.1 403 Forbidden Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 10:19:27 GMT Connection: keep-alive {"error_code":403002,"message":"用戶已禁用"}
應該
在返回的錯誤信息中,同時包含面向開發者和麪向用戶的提示信息,前者可方便開發人員調試,後者可直接展現給終端用戶查看如:
{ "message": "直接展現給終端用戶的錯誤信息", "error_code": "業務錯誤碼", "error": "供開發者查看的錯誤信息", "debug": [ "錯誤堆棧,必須開啓 debug 才存在" ] }
下面詳細列舉了各類狀況 API 的返回說明。
200
狀態碼是最多見的 HTTP
狀態碼,在全部 成功 的 GET
請求中,必須
返回此狀態碼。HTTP
響應實體部分 必須
直接就是數據,不要作多餘的包裝。
錯誤示例:
HTTP/1.1 200 ok Content-Type: application/json Server: example.com { "user": { "id":1, "nickname":"fwest", "username": "example" } }
正確示例:
一、獲取單個資源詳情
{ "id": 1, "username": "godruoyi", "age": 88, }
二、獲取資源集合
[ { "id": 1, "username": "godruoyi", "age": 88, }, { "id": 2, "username": "foo", "age": 88, } ]
三、額外的媒體信息
{ "data": [ { "id": 1, "avatar": "https://lorempixel.com/640/480/?32556", "nickname": "fwest", "last_logined_time": "2018-05-29 04:56:43", "has_registed": true }, { "id": 2, "avatar": "https://lorempixel.com/640/480/?86144", "nickname": "zschowalter", "last_logined_time": "2018-06-16 15:18:34", "has_registed": true } ], "meta": { "pagination": { "total": 101, "count": 2, "per_page": 2, "current_page": 1, "total_pages": 51, "links": { "next": "http://api.example.com?page=2" } } } }
其中,分頁和其餘額外的媒體信息,必須放到
meta
字段中。
當服務器建立數據成功時,應該
返回此狀態碼。常見的應用場景是使用 POST
提交用戶信息,如:
等,均可以返回 201
狀態碼。須要注意的是,你能夠選擇在用戶建立成功後返回新用戶的數據
HTTP/1.1 201 Created Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Date: Sun, 24 Jun 2018 09:13:40 GMT Connection: keep-alive { "id": 1, "avatar": "https:\/\/lorempixel.com\/640\/480\/?32556", "nickname": "fwest", "last_logined_time": "2018-05-29 04:56:43", "created_at": "2018-06-16 17:55:55", "updated_at": "2018-06-16 17:55:55" }
也能夠返回一個響應實體爲空的 HTTP Response
如:
HTTP/1.1 201 Created Server: nginx/1.11.9 Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Date: Sun, 24 Jun 2018 09:12:20 GMT Connection: keep-alive
這裏咱們
應該
採用第二種方式,由於大多數狀況下,客戶端只須要知道該請求操做成功與否,並不須要返回新資源的信息。
該狀態碼錶示服務器已經接受到了來自客戶端的請求,但還未開始處理。經常使用短信發送、郵件通知、模板消息推送等這類很耗時須要隊列支持的場景中;
返回該狀態碼時,響應實體
必須
爲空。
HTTP/1.1 202 Accepted Server: nginx/1.11.9 Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Date: Sun, 24 Jun 2018 09:25:15 GMT Connection: keep-alive
該狀態碼錶示響應實體不包含任何數據,其中:
DELETE
方法刪除資源 成功 時,必須
返回該狀態碼PUT
、PATCH
方法更新數據 成功 時,也 應該
返回此狀態碼HTTP/1.1 204 No Content Server: nginx/1.11.9 Date: Sun, 24 Jun 2018 09:29:12 GMT Connection: keep-alive
全部 API
不應
返回 3xx
類型的狀態碼。由於 3xx
類型的響應格式通常爲下列格式:
HTTP/1.1 302 Found Server: nginx/1.11.9 Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 09:41:50 GMT Location: https://example.com Connection: keep-alive <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="refresh" content="0;url=https://example.com" /> <title>Redirecting to https://example.com</title> </head> <body> Redirecting to <a href="https://example.com">https://example.com</a>. </body> </html>
全部 API
必定不可
返回純 HTML
結構的響應;若必定要使用重定向功能,能夠
返回一個響應實體爲空的 3xx
響應,並在響應頭中加上 Location
字段:
HTTP/1.1 302 Found Server: nginx/1.11.9 Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Date: Sun, 24 Jun 2018 09:52:50 GMT Location: https://godruoyi.com Connection: keep-alive
因爲明顯的客戶端錯誤(例如,請求語法格式錯誤、無效的請求、無效的簽名等),服務器 應該
放棄該請求。
當服務器沒法從其餘 4xx 類型的狀態碼中找出合適的來表示錯誤類型時,都
必須
返回該狀態碼。
HTTP/1.1 400 Bad Request Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 13:22:36 GMT Connection: keep-alive {"error_code":40000,"message":"無效的簽名"}
該狀態碼錶示當前請求須要身份認證,如下狀況都 必須
返回該狀態碼。
客戶端在收到401
響應後,都應該
提示用戶進行下一步的登陸操做。
HTTP/1.1 401 Unauthorized Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked WWW-Authenticate: JWTAuth Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 13:17:02 GMT Connection: keep-alive {"message":"Token Signature could not be verified.","error_code": "40100"}
該狀態碼能夠簡單的理解爲沒有權限訪問該請求,服務器收到請求但拒絕提供服務。
如當普通用戶請求操做管理員用戶時,必須
返回該狀態碼。
HTTP/1.1 403 Forbidden Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 13:05:34 GMT Connection: keep-alive {"error_code":40301,"message":"權限不足"}
該狀態碼錶示用戶請求的資源不存在,如
都 必須
返回該狀態碼,若該資源已永久不存在,則 應該
返回 410
響應。
當客戶端使用的 HTTP
請求方法不被服務器容許時,必須
返回該狀態碼。
如客戶端調用了
POST
方法來訪問只支持 GET 方法的 API
該響應 必須
返回一個 Allow
頭信息用以表示出當前資源可以接受的請求方法的列表。
HTTP/1.1 405 Method Not Allowed Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Allow: GET, HEAD Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 12:30:57 GMT Connection: keep-alive {"message":"405 Method Not Allowed","error_code": 40500}
API
在不支持客戶端指定的數據格式時,應該返回此狀態碼。如支持 JSON
和 XML
輸出的 API
被指定返回 YAML
格式的數據時。
Http 協議通常經過請求首部的 Accept 來指定數據格式
客戶端請求超時時 必須
返回該狀態碼,須要注意的時,該狀態碼錶示 客戶端請求超時,在涉及第三方 API
調用超時時,必定不可
返回該狀態碼。
該狀態碼錶示由於請求存在衝突沒法處理。如經過手機號碼提供註冊功能的 API
,當用戶提交的手機號已存在時,必須
返回此狀態碼。
HTTP/1.1 409 Conflict Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 12:19:04 GMT Connection: keep-alive {"error_code":40900,"message":"手機號已存在"}
和 404
相似,該狀態碼也表示請求的資源不存在,只是 410
狀態碼進一步表示所請求的資源已不存在,而且將來也不會存在。在收到 410
狀態碼後,客戶端 應該
中止再次請求該資源。
該狀態碼錶示服務器拒絕處理當前請求,由於該請求提交的實體數據大小超過了服務器願意或者可以處理的範圍。
此種狀況下,服務器能夠關閉鏈接以避免客戶端繼續發送此請求。
若是這個情況是臨時的,服務器 應該
返回一個 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":"不容許上傳的圖片格式"}
該狀態碼錶示用戶請求次數超過容許範圍。如 API
設定爲 60次/分鐘
,當用戶在一分鐘內請求次數超過 60 次後,都 應該
返回該狀態碼。而且也 應該
在響應首部中加上下列頭部:
X-RateLimit-Limit: 10 請求速率(由應用設定,其單位通常爲小時/分鐘等,這裏是 10次/5分鐘) X-RateLimit-Remaining: 0 當前剩餘的請求數量 X-RateLimit-Reset: 1529839462 重置時間 Retry-After: 120 下一次訪問應該等待的時間(秒)
列子
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.","error_code":42900}
必須
爲全部的 API 設置 Rate Limit 支持。
該狀態碼 必須
在服務器出錯時拋出,對於全部的 500
錯誤,都 應該
提供完整的錯誤信息支持,也方便跟蹤調試。
該狀態碼錶示服務器暫時處理不可用狀態,當服務器須要維護或第三方 API
請求超時/不可達時,都 應該
返回該狀態碼,其中如果主動關閉 API 服務,應該
在返回的響應首部加上 Retry-After
頭部,表示多少秒後能夠再次訪問。
HTTP/1.1 503 Service Unavailable Server: nginx/1.11.9 Content-Type: application/json Transfer-Encoding: chunked Cache-Control: no-cache, private Date: Sun, 24 Jun 2018 10:56:20 GMT Retry-After: 60 Connection: keep-alive {"error_code":50300,"message":"服務維護中"}
其餘 HTTP
狀態碼請參考 HTTP 狀態碼- 維基百科。
版權聲明:自由轉載-非商用-非衍生-保持署名( 創意共享3.0許可證)
Principles of good RESTful API Design(譯)
MIT License
Copyright (c) 2018 godruoyi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.