以下內容以json api規範爲基礎
返回數據
將實際數據放在data中,例如
普通單數data
GET /epics/1
響應
{
"data": {
"id": 1,
"name": "epic1"
}
}
普通複數data
GET /epics
響應
{
"data": [{
"id": 1,
"name": "epic1"
}, {
"id": 2,
"name": "epic2"
}]
}
如何表達關係
GET /epics/1
返回嵌入式規範的數據,這裏選用嵌入式的原因:
- 對客戶來說最方便。 是可以直接通過關係來獲取實際數據。其他方式需要客戶端自行拼接
響應
{
"data": [{
"id": 1,
"name": "用戶故事1",
"epic": {
"id": 5,
"name": "epic5"
},
"subTask": [{
"id": 12,
"name": "子任務12"
}, {
"id": 13,
"name": "子任務13"
}]
}]
}
分頁
此處涉及兩種分頁形式
1、基於偏移量的
# 返回30至45的epics
/epics?offset=30&limit=15
# 如果未填參數,則可使用默認值(offset=0, limit=100 )
/epics
響應
{
"pagination": {
"offset": 30,
"limit": 15,
"total": 999,
},
"data": [
//...
],
"links": {
"next": "/epics?offset=45&limit=15",
"prev": "/epics?offset=15&limit=15"
}
}
缺點
- 數據量大時SQL偏移子句執行會很慢
- 分頁期間的數據變更,需要調用方自行維護
- 不安全,暴露邏輯,容易造成攻擊或者注入
2、基於光標量的-推薦
第一步
/epics?pageSize=100
# 客戶端接受最靠前的100條epic信息
響應(假設sortId字段作爲排序的索引)
{
"pagination": {
"continuationToken": "1504224000000_10",
//其他分頁信息比如搜索信息,排序等
},
"data": [
// ...
// last element:
{ "id": 10, "sortId": 1504224000000 }
],
"links": {
"next": "http://www.shopin.net/epics?pageSize=100&continue=1504224000000_10"
}
}
下一頁鏈接使API真正成爲RESTful風格,因爲客戶端只需通過這些鏈接(HATEOAS)即可查看集合。 無需手動構建URL。 此外,服務端可以簡單地更改URL結構而不會破壞客戶端,保證接口的演進性。
此處對兩個概念做簡單的介紹
- HATEOAS(超媒體動態):原則就是客戶端與服務器的交互完全由超媒體動態提供,客戶端無需事先了解如何與數據或者服務器交互。例如,想要訪問id爲21的epic的用戶story清單,我需要提前知曉請求方式爲(/epics/21/stories),這種字符串拼接容易出錯,相對脆弱,難以維護,如果語義或者概念發生變化,則直接導致資源無法鏈接或者說API崩掉。更好的做法是在響應中提供客戶可以跟進的鏈接,即‘links’的內容
- API的可演進性:避免了破壞性的變更,更好的向後兼容,只要客戶端合理的使用links而非手動構建url,則不會破壞客戶端。另外一點很實用:方便在現有的資源下創建新的資源,而不需要客戶端配合邏輯上的變更,比如story下增加一個名爲user的resource,則不需要依賴客戶端更新邏輯,也就是說保證了業務邏輯更好的側重在服務端。
返回錯誤信息(根據RFC7807:API錯誤處理最佳實踐)
錯誤響應將具有以下內容(不代表具體鍵(json key)的值):
- type(String):描述錯誤條件的文檔的URL(可選,如果沒有提供,則假定“about:blank”;應可被解析爲可讀文檔)。
- title(String):般錯誤類型的簡短易讀的標題;對於給定的類型,標題不應改變。
- status(String或者numbr):HTTP狀態碼;這是爲了使所有信息都在一個地方,不在body裏。
- detail(String):細節,可以根據實際情況定製,必須易讀
- 其他自定義的內容(可選)
例如
GET /epics?state=unknow
響應
// 400 Bad Request
{
"type": "http://jira.com/error/1001",
"title": "參數無效",
"exception": "org.springframework.web.bind.MethodArgumentNotValidException",
"code": 10001,
"httpStatus": "400 BAD_REQUEST",
"detail": {
"errors": [
{
"fieldName": "nickname",
"message": "不能爲空"
},
{
"fieldName": "pwd",
"message": "不能爲空"
},
{
"fieldName": "pwd",
"message": "密碼格式有誤"
},
{
"fieldName": "nickname",
"message": "長度需要在1和64之間"
}
]
}
}
返回HTTPSTATUS
使用所有過多的HTTP狀態碼可能會讓API用戶感到困惑。所以應該保持使用精簡的HTTP狀態碼集
常見的狀態碼解釋如下
2XX 一切正常
- 200 OK
- 不同請求方式對於請求成功的意義不同
- GET:資源已被獲取並在消息正文中
- HEAD:響應的消息體爲頭部信息
- POST:響應的消息體中包含此次請求的結果
- 不用在PUT和DELETE方法中
- 201 Created
- 該請求已成功,並因此創建了一個新的資源。這通常是在POST請求,或是某些PUT請求(某PUT請求在更新資源的同時會創建新的資源的時候)之後返回的響應。
- 202 Accepted
- 表示服務器端已經收到請求消息,但是尚未進行處理。但是對於請求的處理確實無保證的,即稍後無法通過 HTTP 協議給客戶端發送一個異步請求來告知其請求的處理結果。這個狀態碼被設計用來將請求交由另外一個進程或者服務器來進行處理,或者是對請求進行批處理的情形
- 不可用於主數據變價下發場景等類似場景。
- 204 No Content
- 對不會返回響應體的成功請求進行響應,常用場景如下
- DELETE請求
- PUT 請求中進行資源更新,但是不需要改變當前展示給用戶的頁面,但是如果新創建了資源,那麼返回 201 Created 。如果頁面需要更新以反映更新後的資源,那麼需要返回 200 OK
4XX 客戶端錯誤
- 400 Bad Request
- 語義有誤,當前請求無法被服務器理解。除非進行修改,否則客戶端不應該重複提交這個請求。
- 請求參數有誤。
- 401 Unauthorized
- 沒有進行認證或者認證非法。當API通過瀏覽器訪問的時候,可以用來彈出一個認證對話框
- 這個狀態碼會與 WWW-Authenticate 首部一起發送,其中包含有如何進行驗證的信息。RFC 7235, section 3.1: 401 Unauthorized
- 403 Forbidden
- 服務器已經理解請求,但是拒絕執行它。與 401 響應不同的是,身份驗證並不能提供任何幫助,或者說身份驗證通過了,但是依然拒絕執行。這個請求不應該被重複提交。
- 例如不正確的密碼、短信驗證失敗等場景
- 404 Not Found
- 找不到此資源,且不能說明是否永久找不到。
- 當服務器不想告知到底爲何請求被拒絕或者沒有其他適合的響應可用的情況下使用
- 405 Method Not Allowed
- 請求方法不能被用於請求相應的資源
- 該響應必須返回一個Allow 頭信息用以表示出當前資源能夠接受的請求方法的列表
- GET 與 HEAD 兩個方法不得被禁止,當然也不得返回狀態碼 405。
- 410 Gone
- 被請求的資源在服務器上已經不再可用,而且沒有任何已知的轉發地址
- 永久性的
- 響應默認會被緩存
5XX 服務器錯誤
- 500 Internal Server Error
- 服務器內部錯誤,無法完成請求