寫在前面
工作中使用 Laravel 開發 API 專案已經有些年頭了,發現每次啟動新的 Api 專案的時都會在 Laravel 基礎上進行一些預處理,包括針對 API 專案的結構設計,統一響應結構的封裝,異常的捕獲處理以及授權模組的配置等。總是在做一些重複的工作,那索性將這些常用的基礎封裝做成一個「啟動模板」好了。
專案地址:戳這兒
為什麼是 Lumen ?
現如今,中大型專案中通常使用前後端分離方式開發,前後端分別通過不同的程式碼倉庫各自維護著專案程式碼,Laravel 只負責專案中的 API 部分,提供 API 給前端呼叫。這種場景下,使用 Laravel 進行開發 API 稍微顯得有點“臃腫”了。
相比之下,Lumen 針對專案中的 API 開發場景,精簡了Laravel 中的很多部分,更適合 API 開發。有了 Laravel 使用經驗,切換到 Lumen 也較為容易。
概覽
- 適配 Laravel 7 中新增的 HttpClient 客戶端
- 使用 Laravel 原生的 Api Resource
- 規範統一的響應結構
- 使用 Jwt-auth 方式授權
- 支援日誌記錄到 MongoDB
- 合理有效地『Repository & Service』架構設計(?)
規範的響應結構
摘選自:RESTful 服務最佳實踐
code——包含一個整數型別的HTTP響應狀態碼。
status——包含文字:”success”,”fail”或”error”。HTTP狀態響應碼在500-599之間為”fail”,在400-499之間為”error”,其它均為”success”(例如:響應狀態碼為1XX、2XX和3XX)。
message——當狀態值為”fail”和”error”時有效,用於顯示錯誤資訊。參照國際化(il8n)標準,它可以包含資訊號或者編碼,可以只包含其中一個,或者同時包含並用分隔符隔開。
data——包含響應的body。當狀態值為”fail”或”error”時,data僅包含錯誤原因或異常名稱。
說明
整體響應結構設計參考如上,相對嚴格地遵守了 RESTful 設計準則,返回合理的 HTTP 狀態碼。
考慮到業務通常需要返回不同的“業務描述處理結果”,在所有響應結構中都支援傳入符合業務場景的message
。
- data:
- 查詢單條資料時直接返回物件結構,減少資料層級;
- 查詢列表資料時返回陣列結構;
- 建立或更新成功,返回修改後的資料;(也可以不返回資料直接返回空物件)
- 刪除成功時返回空物件
- status:
- error, 客服端出錯,HTTP 狀態響應碼在400-599之間。如,傳入錯誤引數,訪問不存在的資料資源等
- fail,服務端出錯,HTTP 狀態響應碼在500-599之間。如,程式碼語法錯誤,空物件呼叫函式,連線資料庫失敗,undefined index等
- success, HTTP 響應狀態碼為1XX、2XX和3XX,用來表示業務處理成功。
- message: 描述執行的請求操作處理的結果;也可以支援國際化,根據實際業務需求來切換。
- code: HTTP 響應狀態碼;可以根據實際業務需求,調整成業務操作碼
使用
在需要進行 HTTP 響應的地方使用 \\App\\Traits\\Helpers
對\\App\\Http\\Response
中封裝的響應方法進行呼叫。
通常使用是在 Controller 層中根據業務處理的結果進行響應,所以在 \\App\\Http\\Controllers
基類中已經引入了 Helpers
trait,可以直接在 Controller 中進行如下呼叫:
// 操作成功情況
$this->response->success($data,$message);
$this->response->created($data,$message);
$this->response->accepted($message);
$this->response->noContent($message);
// 操作失敗或異常情況
$this->response->fail($message);
$this->response->errorNotFound();
$this->response->errorBadRequest();
$this->response->errorForbidden();
$this->response->errorInternal();
$this->response->errorUnauthorized();
$this->response->errorMethodNotAllowed();
操作成功時的響應結構
- 返回單條資料
{
"data": {
"nickname": "Jiannei",
"email": "longjian.huang@foxmail.com"
},
"status": "success",
"code": 200,
"message": "成功"
}
- 返回列表資料
{
"data": [
{
"nickname": "Jiannei",
"email": "longjian.huang@foxmail.com"
},
{
"nickname": "Qian",
"email": "1234567891@foxmail.com"
},
{
"nickname": "Turbo",
"email": "123456789@foxmail.com"
}
// ...
],
"links": {
"first": "http://lumen-api.test/users?page=1",
"last": null,
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"path": "http://lumen-api.test/users",
"per_page": 15,
"to": 13
},
"status": "success",
"code": 200,
"message": "成功"
}
操作失敗時的響應結構
{
"status": "fail",
"code": 500,
"message": "Service error",
"data": {}
}
異常捕獲時的響應結構
整體格式與業務操作成功和業務操作失敗時的一致,相比失敗時,data 部分會增加額外的異常資訊展示,方便專案開發階段進行快速地問題定位。
- 自定義實現了
ValidationException
的響應結構
{
"status": "error",
"code": 422,
"message": "Validation error",
"data": {
"email": [
"The email has already been taken."
],
"password": [
"The password field is required."
]
}
}
NotFoundException
異常捕獲的響應結構
關閉 debug 時:
{
"status": "error",
"code": 404,
"message": "Service error",
"data": {
"message": "No query results for model [App\\Models\\User] 19"
}
}
開啟 debug 時:
{
"status": "error",
"code": 404,
"message": "Service error",
"data": {
"message": "No query results for model [App\\Models\\User] 19",
"exception": "Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException",
"file": "/var/www/lumen-api-starter/vendor/laravel/lumen-framework/src/Exceptions/Handler.php",
"line": 107,
"trace": [
{
"file": "/var/www/lumen-api-starter/app/Exceptions/Handler.php",
"line": 55,
"function": "render",
"class": "Laravel\\Lumen\\Exceptions\\Handler",
"type": "->"
},
{
"file": "/var/www/lumen-api-starter/vendor/laravel/lumen-framework/src/Routing/Pipeline.php",
"line": 72,
"function": "render",
"class": "App\\Exceptions\\Handler",
"type": "->"
},
{
"file": "/var/www/lumen-api-starter/vendor/laravel/lumen-framework/src/Routing/Pipeline.php",
"line": 50,
"function": "handleException",
"class": "Laravel\\Lumen\\Routing\\Pipeline",
"type": "->"
}
// ...
]
}
}
- 其他型別異常捕獲時的響應結構
{
"status": "fail",
"code": 500,
"message": "syntax error, unexpected '$user' (T_VARIABLE)",
"data": {
"message": "syntax error, unexpected '$user' (T_VARIABLE)",
"exception": "ParseError",
"file": "/var/www/lumen-api-starter/app/Http/Controllers/UsersController.php",
"line": 34,
"trace": [
{
"file": "/var/www/lumen-api-starter/vendor/composer/ClassLoader.php",
"line": 322,
"function": "Composer\\Autoload\\includeFile"
},
{
"function": "loadClass",
"class": "Composer\\Autoload\\ClassLoader",
"type": "->"
},
{
"function": "spl_autoload_call"
}
// ...
]
}
}
特別說明:使用 Postman 等 Api 測試工具的使用需要新增 X-Requested-With:XMLHttpRequest
或者Accept:application/json
header 資訊來表明是 Api 請求,否則在異常捕獲到後返回的可能不是預期的 JSON 格式響應。
豐富的日誌模式支援
Repository & Service 模式架構
使用了andersao/l5-repository 進行進行專案結構設計,補充新增了 Service 層。
職責說明
待補充。
規範
命名規範:待補充
使用規範:待補充
Packages
其他
依照慣例,如對您的日常工作有所幫助或啟發,歡迎單擊三連 star + fork + follow
。
如果有任何批評建議,通過郵箱(longjian.huang@foxmial.com)的方式(如果我每天堅持看郵件的話)可以聯絡到我。
總之,歡迎各路英雄好漢。
參考
本作品採用《CC 協議》,轉載必須註明作者和本文連結