
API開發中的日志記錄價值
GET /user/info/1 ID 查詢,如需查詢多個,ID 列表通過 Query 參數傳遞,形如 ids=1,2,3
POST /user/create 創建
POST /user/update/1 更新,只更新傳遞的字段,未傳遞的字段保持不變
POST /user/replace/1 替換,整體更新,未傳遞的字段將清空
POST /user/delete/1 刪除,如需刪除多個,ID 列表通過請求體傳遞,形如 {"ids": [1, 2, 3]}
GET /user/list?gender=male&minAge=18
GET /user/infoByUsername?username=jack
GET /user/follow?followingId=1&followerId=2 涉及到多個 ID 組合才能定位資源時,統一通過 Query 參數傳遞
POST /user/sendVerifyCode
對于采用微服務架構的應用,需要通過路徑前綴來區分前后端資源,以及不同的微服務。
/api
路徑前綴下,可在反向代理層添加該前綴,在傳遞給后端服務時抹去該前綴,以便該前綴對后端服務來說無感知。/user
),該前綴同樣對各微服務來說無感知。/user/create
(對外暴露的完整路徑為 /api/user/user/create
,這里服務名和模塊名同名)。對于內部使用的 API,自己可以控制客戶端升級節奏,應避免使用 API 版本,因為維護多版本 API 的成本很高。對于對外開放的 API,由于無法控制使用方客戶端升級節奏,那么可以通過多版本 API 來實現平滑升級,在廢棄老版 API 之前給使用方留足夠的升級時間。
API 版本號可在不同的層級上添加,以前面的創建用戶 API /api/user/user/create
為例,按作用范圍由大到小有以下幾種方式:
/api/v1/user/user/create
在應用網關層級添加(推薦)。/api/user/v1/user/create
在微服務層級添加。/api/user/user/v1/create
在模塊層級添加。/api/user/user/create/v1
在 API 層級添加。不建議為不同版本的服務啟動不同的實例,隨著版本的不斷升級,后期的維護工作會越來越大。對于同一個服務的不同版本 API,應使用一套代碼,新版 API Controller 可以通過繼承老版 Controller 來盡量復用現有代碼。
通過 HTTP 頭來傳遞公共參數,優先使用 HTTP 標準頭,沒有合適的再自定義,自定義 HTTP 頭需以 X- 打頭。
HTTP 頭 | 示例 | 用途 |
Authorization | Bearer | 認證服務頒發的 Token |
Accept-Language | zh-CN,zh;q=0.9,en-US,en;q=0.1 | 可接受的響應內容語言,優先使用權重高的 |
X-Client-Name | BasicAI | 客戶端名稱 |
X-Client-Version | v1.0.0 | 客戶端版本 |
示例:
{
"username": "jack",
"password": "12345678",
"age": 17
}
HTTP 狀態碼設計的初衷是用于靜態資源訪問場景,對于 API 這種動態服務場景,許多狀態碼都不適用,或者根本無法表示各種千奇百怪的業務錯誤。因此這里推薦只使用下面這些少量的 HTTP 狀態碼,其它業務異常情況統一響應 200 狀態碼,并在響應體里通過 code 返回具體的業務錯誤碼。
響應體為 JSON 對象,結構如下:
{
"code": "OK", // 業務錯誤碼
"message": "", // 業務錯誤描述
"data": null // 業務數據
}
USER__USER__USERNAME_DUPLICATED
,其中前兩級依次為服務和模塊,一些與服務和模塊無關的公共錯誤碼沒有前綴。data
字段返回,這樣可以讓后端省去大量的包裝類定義,如果有多項那么只能再包一層,在 data
下通過不同字段區分,如果沒有則為 null
。單項業務數據直接通過 data 字段返回示例:
{
"code": "OK",
"message": "",
"data": {
"id": 1,
"username": "jack"
}
}
多項業務數據需包一層示例:
{
"code": "OK",
"message": "",
"data": {
"user": {
"id": 1,
"username": "jack"
},
"roles": []
}
}
列表數據示例:
{
"code": "OK",
"message": "",
"data": {
"list": [],
"total": 1000
}
}
業務出錯示例:
{
"code": "BILLING__PAY__MONEY_NOT_ENOUGH",
"message": "money not enough",
"data": null
}
適合客戶端有翻頁條,按頁展示數據,數據集變化較慢的場景。
total
、pageNo
、pageSize
、list
來傳遞和返回總數(可選)、當前頁碼、每頁條數和當頁數據。{
"code": "ok",
"message": "",
"data": {
"total": 100,
"pageNo": 1,
"pageSize": 10,
"list": []
}
}
適合沒有翻頁條的流式加載模式場景,如果起始位置使用主鍵 ID、創建時間這樣的排序字段,服務端可以通過大于或等于比較來加速查詢,并且在數據集有變化時能夠保證分批獲取的數據不重復。
total
、offset
、limit
、list
來傳遞和返回總數(可選)、起始位置、返回條數和當頁數據。{
"code": "ok",
"message": "",
"data": {
"total": 100,
"offset": 0,
"limit": 10,
"list": []
}
}
假設我們正在設計一個電商平臺的微服務架構,其中包括用戶服務、訂單服務和支付服務。每個服務都有自己的 API,這些 API 通過 RESTful 設計原則進行設計,并實現了 OAuth 2.0 身份認證。我們為每個服務提供了詳細的 Swagger 文檔,并在持續集成過程中運行自動化測試,以確保各個服務間的交互順暢。
POST /api/user/user/create
Content-Type: application/json
{
"username": "jack",
"password": "12345678",
"age": 17
}
GET /api/user/user/info/1
POST /api/order/order/create
Content-Type: application/json
{
"userId": 1,
"items": [
{
"itemId": 101,
"quantity": 2
},
{
"itemId": 102,
"quantity": 1
}
]
}
GET /api/order/order/list?userId=1
POST /api/payment/payment/create
Content-Type: application/json
{
"orderId": 1,
"amount": 100
}
GET /api/payment/payment/status/1
微服務架構下的 API 設計需要綜合考慮資源管理、版本控制、安全性、錯誤處理以及文檔和測試等多個方面。通過遵循這些最佳實踐,我們可以構建出高效、可靠的 API,從而支持系統的可擴展性和靈活性。希望本文對您有所幫助,并為您的微服務架構設計提供了一些有價值的信息和見解。