背景
- 傳統的RPC API設計偏向于傳統的C/S架構,對于B/S模式的WEB應用已經不適用
- 需要一種全新的結構清晰、符合標準、易于理解、擴展方便的設計準則
RESTful API
-
RESTful API是目前比較成熟的一套互聯網應用程序的API設計理論 - 符合
REST設計理念的WEB API,我們稱之為RESTful API - REST的全稱是
Representational State Transfer,即表述性狀態(tài)轉移
Representational State Transfer
-
Representational,即Resource的表現層,用于表述資源的一種方式- 常用的表述方式有,JSON|XML|HTML|TEXT等
-
Resource,就是網絡上的一個實體,或者說是網絡上的一個具體信息- 可以是一個文本|圖片|歌曲|服務,總之就是一個具體的實體
- 可以用一個URI(統一資源定位符)指向它,每種資源對應一個特定的URI
- 要獲取這個資源,訪問它的URI就可以,因此URI就成了每一個Resource的地址或獨一無二的識別符
- State Transfer,即狀態(tài)轉化
- 訪問一個網站,就代表了客戶端和服務器的一個互動過程,過程中勢必涉及到數據和狀態(tài)的變化
- 互聯網通信協議HTTP協議,是一個無狀態(tài)協議,這意味著,所有的狀態(tài)都保存在服務器端
- 因此,如果客戶端想要操作服務器,必須通過某種手段,讓服務器端發(fā)生"狀態(tài)轉化"(State Transfer)。而這種轉化是建立在表現層之上的,所以就是"表現層狀態(tài)轉化"
HTTP操作
狀態(tài)轉化由HTTP操作實現,并不由URI地址表示
| 操作 | HTTP Method | URI |
|---|---|---|
| 獲取列表數據 | GET | /collection |
| 添加數據 | POST | /collection |
| 查看數據 | GET | /collection/{id} |
| 修改全量數據 | PUT | /collection/{id} |
| 修改部分數據 | PATCH | /collection/{id} |
| 刪除數據 | DELETE | /collection/{id} |
注:其中collection指資源集合(復數形式),比如users、materials、groups
常見錯誤集:
# 路徑中存在動作詞
POST /insert_material
# 不應用單數,應用集合(復數)
POST /material
# PUT是全量更新,此時會導致所有沒有值的屬性都被置空,而本意是改一個屬性
PUT /materials/{id}
body:{"location":"A1"}
# 網上匯款,從賬戶1向賬戶2匯款500元,動詞不應該在URI中
POST /accounts/1/transfer/500/to/2
# 正確的寫法是將操作服務化
POST /transaction
body:{from:1, to:2, amount:500.00}
HTTP操作延伸
由于RESTful中,只能對單一資源進行,但是實際應用中又有大量的批量場景,因此對RESTful進行擴展,增加一個服務:batch
注:該定義非RESTful準則,僅用于自己項目內部約定,供參考
| 操作 | HTTP Method | URI |
|---|---|---|
| 添加數據 | POST | /collection/batch |
| 修改全量數據 | PUT | /collection/batch |
| 修改部分數據 | PATCH | /collection/batch |
| 刪除數據 | DELETE | /collection/{id},{id},... |
過濾信息(Filtering)
如果記錄數量很多,服務器不可能都將它們返回給用戶。API應該提供參數,過濾返回結果,下面是一些常見的參數:
- ?limit=10:指定返回記錄的數量
- ?offset=10:指定返回記錄的開始位置。
- ?page=2&per_page=100:指定第幾頁,以及每頁的記錄數。
- ?sortby=name&order=[asc|desc]:指定返回結果按照哪個屬性排序,以及排序順序
- ?animal_type_id=1:指定篩選條件
返回結果
針對不同操作,服務器向用戶返回的結果應該符合以下規(guī)范:
- GET /collection:返回資源對象的列表(數組)
- GET /collection/resource:返回單個資源對象
- POST /collection:返回新生成的資源對象
- PUT /collection/resource:返回完整的資源對象
- PATCH /collection/resource:返回完整的資源對象
- DELETE /collection/resource:返回一個空文檔
針對批量操作:
- POST /collection/patch:返回新生成的資源對象列表
- PUT /collection/patch:返回完整的資源對象列表
- PATCH /collection/patch:返回完整的資源對象列表
- DELETE /collection/{id},{id}:返回一個所有資源刪除成功與否的結果列表
狀態(tài)碼(Status Codes)
服務器向用戶返回的狀態(tài)碼和提示信息,常見的有以下一些(方括號中是該狀態(tài)碼對應的HTTP動詞):
- 200 OK - [GET]:服務器成功返回用戶請求的數據,該操作是冪等的(Idempotent)
- 201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數據成功。
- 202 Accepted - [*]:表示一個請求已經進入后臺排隊(異步任務)
- 204 NO CONTENT - [DELETE]:用戶刪除數據成功。
- 400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發(fā)出的請求有錯誤,服務器沒有進行新建或修改數據的操作,該操作是冪等的。
- 401 Unauthorized - [*]:表示用戶沒有權限(令牌、用戶名、密碼錯誤)。
- 403 Forbidden - [*] 表示用戶得到授權(與401錯誤相對),但是訪問是被禁止的。
- 404 NOT FOUND - [*]:用戶發(fā)出的請求針對的是不存在的記錄,服務器沒有進行操作,該操作是冪等的。
- 406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式,但是只有XML格式)。
- 410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再得到的。
- 422 Unprocesable entity - [POST/PUT/PATCH] 當創(chuàng)建一個對象時,發(fā)生一個驗證錯誤。
- 500 INTERNAL SERVER ERROR - [*]:服務器發(fā)生錯誤,用戶將無法判斷發(fā)出的請求是否成功
狀態(tài)碼的完全列表參見這里
域名
應該盡量將API部署在專用域名之下,如:
- http(s)://api.example.com/
如果確定API很簡單,不會有進一步擴展,可以考慮放在主域名下:
- http(s)://www.example.com/api/
版本號
應該將API的版本號放入URL,如:
另一種做法是,將版本號放在HTTP頭信息中,但不如放入URL方便和直觀,如:
- https://api.example.com/
- Accept: vnd.example-com.foo+json; version=1.0