技術 5 分鐘閱讀
Laravel API 設計最佳實踐:從 RESTful 到版本控制
前言
最近在幫客戶開發需要提供 API 的專案越來越多。整理了一些目前覺得不錯的 API 設計原則,特別針對 Laravel 框架。
RESTful 路由命名
基本原則
// routes/api.php
Route::prefix('v1')->group(function () {
Route::apiResource('products', ProductController::class);
Route::apiResource('orders', OrderController::class);
Route::apiResource('orders.items', OrderItemController::class);
});
產生的路由:
| Method | URI | Action |
|---|---|---|
| GET | /api/v1/products | index |
| POST | /api/v1/products | store |
| GET | /api/v1/products/{id} | show |
| PUT | /api/v1/products/{id} | update |
| DELETE | /api/v1/products/{id} | destroy |
命名原則
- 用名詞複數:
/products而非/product - 巢狀資源不要超過兩層
- 查詢用 query string:
/products?category=food&sort=price
API Resource(回應格式)
// app/Http/Resources/ProductResource.php
class ProductResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'description' => $this->description,
'category' => new CategoryResource($this->whenLoaded('category')),
'created_at' => $this->created_at->toISOString(),
];
}
}
在 Controller 中使用:
public function index()
{
$products = Product::with('category')->paginate(15);
return ProductResource::collection($products);
}
public function show(Product $product)
{
return new ProductResource($product->load('category'));
}
統一錯誤處理
// app/Exceptions/Handler.php
public function render($request, Throwable $e)
{
if ($request->expectsJson()) {
if ($e instanceof ModelNotFoundException) {
return response()->json([
'error' => '找不到指定的資源',
'code' => 'RESOURCE_NOT_FOUND',
], 404);
}
if ($e instanceof ValidationException) {
return response()->json([
'error' => '驗證失敗',
'code' => 'VALIDATION_ERROR',
'details' => $e->errors(),
], 422);
}
}
return parent::render($request, $e);
}
版本控制
目前覺得最實用的做法是 URL 前綴:
// routes/api.php
Route::prefix('v1')->group(function () {
Route::apiResource('products', V1\ProductController::class);
});
Route::prefix('v2')->group(function () {
Route::apiResource('products', V2\ProductController::class);
});
認證與 Rate Limiting
搭配 Middleware 做好 API 保護:
// routes/api.php
Route::middleware(['auth:sanctum', 'throttle:60,1'])->group(function () {
Route::apiResource('orders', OrderController::class);
});
API 文件
推薦使用 Scribe 自動產生 API 文件:
composer require knuckleswtf/scribe
php artisan vendor:publish --tag=scribe-config
php artisan scribe:generate
搭配前端
如果你的前端使用 React,可以參考 Inertia.js 省去 API 層。但如果是開發給第三方使用的 API,上述的設計原則就很重要了。
小結
好的 API 設計能讓前端開發者(包括未來的自己)更輕鬆。花時間在設計階段把結構想清楚,後續維護會省下大量時間。
如果你需要類似的系統,歡迎聯繫討論。
#Laravel #API #RESTful