API 規格文檔目錄
本目錄包含所有 REST API 端點的詳細規格。
API 文檔列表
| 領域 | 文檔 | 狀態 |
|---|---|---|
| 認證 | authentication.md | ✅ 已完成 |
| 多因素認證 | mfa.md | 🔵 設計中 |
| 訂單管理 | orders.md | ✅ 已完成 |
| 客戶管理 | customers.md | ✅ 已完成 |
| 產品管理 | products.md | ✅ 已完成 |
| 支付管理 | payments.md | 🟡 Phase 2 |
API 設計原則
1. RESTful 風格
- 使用名詞表示資源(不使用動詞)
- 使用 HTTP 方法表達操作意圖
- 遵循 HTTP 狀態碼語義
2. HTTP 方法規範
| 方法 | 用途 | 語意 | 冪等性 | 範例 |
|---|---|---|---|---|
| GET | 讀取資源 | 獲取資源,不改變狀態 | ✅ 冪等 | GET /orders/123 |
| POST | 創建資源 | 創建新資源 | ❌ 非冪等 | POST /orders |
| PUT | 完整替換 | 替換整個資源,需傳所有欄位 | ✅ 冪等 | PUT /orders/123 |
| PATCH | 部分更新 | 只更新指定欄位 | ✅ 冪等 | PATCH /orders/123/status |
| DELETE | 刪除資源 | 刪除指定資源 | ✅ 冪等 | DELETE /orders/123 |
PUT vs PATCH 使用原則
# PUT - 完整替換(需要傳送所有欄位)
PUT /api/v1/orders/123
Content-Type: application/json
{
"customerId": "cust-1",
"items": [...],
"deliveryDate": "2025-12-21",
"deliveryAddress": "...",
"status": "PENDING"
// ... 必須包含所有欄位
}
# PATCH - 部分更新(只傳送要更新的欄位)
PATCH /api/v1/orders/123/status
Content-Type: application/json
{
"status": "CONFIRMED"
}
使用指引:
- ✅ 狀態更新:使用
PATCH(只更新狀態欄位) - ✅ 單一欄位更新:使用
PATCH(如更新備註、地址) - ✅ 完整表單提交:使用
PUT(替換整個資源) - ❌ 避免:用
PUT做部分更新(容易覆蓋未傳送的欄位)
3. 版本控制
- API 路徑包含版本號:
/api/v1/ - 未來重大變更時遞增版本號
4. 多租戶隔離
- 所有請求需包含 JWT Token(含
tenantId) - 後端自動過濾資源(確保 Tenant 隔離)
5. 統一響應格式
成功響應(單一資源)
{
"id": "resource-001",
"name": "資源名稱",
...
}
成功響應(列表資源)
Response Body:
[
{ "id": "resource-001", ... },
{ "id": "resource-002", ... }
]
Response Headers:
X-Total-Count: 100
X-Page: 1
X-Per-Page: 20
Link: </api/v1/resources?page=2>; rel="next", </api/v1/resources?page=5>; rel="last"
錯誤響應
{
"error": "ERROR_CODE",
"message": "錯誤說明",
"field": "fieldName",
"timestamp": "2025-10-31T10:30:00Z"
}
6. 分頁設計規範
所有列表 API 必須使用 HTTP Headers 返回分頁資訊(不在 Response Body 中)
Request Parameters
| 參數 | 類型 | 必填 | 說明 | 預設值 |
|---|---|---|---|---|
| page | integer | No | 頁碼(從 1 開始) | 1 |
| limit | integer | No | 每頁數量(10, 20, 50, 100) | 20 |
| sort | string | No | 排序(如 createdAt:desc) | createdAt:desc |
Response Headers
| Header | 類型 | 說明 | 範例 |
|---|---|---|---|
| X-Total-Count | integer | 總筆數 | 100 |
| X-Page | integer | 當前頁碼 | 1 |
| X-Per-Page | integer | 每頁筆數 | 20 |
| Link | string | 分頁導航連結(RFC 5988) | <...>; rel="next" |
Link Header 格式
Link: </api/v1/resources?page=2&limit=20>; rel="next",
</api/v1/resources?page=5&limit=20>; rel="last",
</api/v1/resources?page=1&limit=20>; rel="first"
rel 值說明:
first: 第一頁prev: 上一頁(僅當 page > 1 時)next: 下一頁(僅當有下一頁時)last: 最後一頁
範例
GET /api/v1/orders?page=2&limit=20&sort=createdAt:desc
Authorization: Bearer {token}
HTTP/1.1 200 OK
X-Total-Count: 100
X-Page: 2
X-Per-Page: 20
Link: </api/v1/orders?page=3&limit=20>; rel="next",
</api/v1/orders?page=5&limit=20>; rel="last",
</api/v1/orders?page=1&limit=20>; rel="first",
</api/v1/orders?page=1&limit=20>; rel="prev"
Content-Type: application/json
[
{ "id": "order-021", ... },
{ "id": "order-022", ... },
...
]
設計理由:
- ✅ 符合 RESTful 最佳實踐(分離元數據與資料)
- ✅ Response Body 更簡潔(直接返回陣列)
- ✅ 支援 HTTP 快取(Headers 可被 CDN/Proxy 快取)
- ✅ 符合 RFC 5988 Link Header 標準
API 文檔模板
# {領域} API
## 概述
(簡述此 API 的用途與適用場景)
---
## 端點列表
| 方法 | 路徑 | 說明 | 權限 |
|------|------|------|------|
| GET | /api/v1/{resource} | 列出資源 | ROLE_XXX |
| GET | /api/v1/{resource}/:id | 獲取單一資源 | ROLE_XXX |
| POST | /api/v1/{resource} | 創建資源 | ROLE_XXX |
| PUT | /api/v1/{resource}/:id | 更新資源 | ROLE_XXX |
| DELETE | /api/v1/{resource}/:id | 刪除資源 | ROLE_XXX |
---
## 端點詳細規格
### GET /api/v1/{resource}
**描述**: 列出所有資源(支援分頁、過濾、排序)
**權限**: `ROLE_STAFF` 或更高
**Query Parameters**:
| 參數 | 類型 | 必填 | 說明 | 預設值 |
|------|------|------|------|--------|
| page | integer | No | 頁碼(從 1 開始) | 1 |
| size | integer | No | 每頁數量 | 20 |
| sort | string | No | 排序欄位(如 createdAt:desc) | createdAt:desc |
| status | string | No | 過濾狀態 | - |
**請求範例**:
\`\`\`http
GET /api/v1/resources?page=1&limit=20&status=active
Authorization: Bearer {token}
\`\`\`
**響應範例** (200 OK):
**Headers**:
\`\`\`
X-Total-Count: 100
X-Page: 1
X-Per-Page: 20
Link: </api/v1/resources?page=2&limit=20>; rel="next", </api/v1/resources?page=5&limit=20>; rel="last"
\`\`\`
**Body**:
\`\`\`json
[
{
"id": "resource-001",
"name": "資源名稱",
...
},
{
"id": "resource-002",
"name": "資源名稱 2",
...
}
]
\`\`\`
**錯誤響應**:
- `401 Unauthorized`: Token 無效或過期
- `403 Forbidden`: 權限不足
---
### POST /api/v1/{resource}
**描述**: 創建新資源
**權限**: `ROLE_STAFF` 或更高
**Request Body**:
\`\`\`json
{
"field1": "value1",
"field2": "value2",
...
}
\`\`\`
**欄位說明**:
| 欄位 | 類型 | 必填 | 說明 | 驗證規則 |
|------|------|------|------|----------|
| field1 | string | Yes | 欄位說明 | 最少 3 字元 |
| field2 | integer | No | 欄位說明 | 範圍 1-100 |
**請求範例**:
\`\`\`http
POST /api/v1/resources
Authorization: Bearer {token}
Content-Type: application/json
{
"field1": "value1",
"field2": 50
}
\`\`\`
**響應範例** (201 Created):
\`\`\`json
{
"id": "resource-001",
"field1": "value1",
"field2": 50,
"createdAt": "2025-10-31T10:30:00Z",
"createdBy": "user-001"
}
\`\`\`
**錯誤響應**:
- `400 Bad Request`: 缺少必填欄位或驗證失敗
- `401 Unauthorized`: Token 無效
- `403 Forbidden`: 權限不足
---
## 通用錯誤碼
| 錯誤碼 | HTTP 狀態 | 說明 |
|--------|-----------|------|
| VALIDATION_ERROR | 400 | 輸入驗證失敗 |
| UNAUTHORIZED | 401 | 未認證或 Token 無效 |
| FORBIDDEN | 403 | 權限不足 |
| RESOURCE_NOT_FOUND | 404 | 資源不存在 |
| CONFLICT | 409 | 資源衝突(如重複創建) |
| INTERNAL_ERROR | 500 | 伺服器內部錯誤 |
---
## 多租戶隔離
所有 API 自動執行 Tenant 隔離:
1. 從 JWT Token 提取 `tenantId`
2. 自動過濾查詢結果(僅返回當前 Tenant 的數據)
3. 創建資源時自動附加 `tenantId`
4. 跨 Tenant 訪問會返回 `404 Not Found`(而非 `403`,避免資訊洩漏)
---
## 速率限制
- 每個 IP 每分鐘最多 100 個請求
- 超過限制返回 `429 Too Many Requests`
---
## 參考資源
- [HTTP 狀態碼](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
- [REST API 設計指南](https://restfulapi.net/)
最後更新: 2025-10-31