「API 是你後端的門面。設計糟的 API 就像沒有菜單的餐廳,客人只能靠猜。 等你的 API 被一百個前端工程師使用之後,改一個 endpoint 名稱就是一場災難。」
很多人第一次寫 API 是這樣的:GET /getUser?userId=123、POST /createNewOrder。 能動,但沒有規範。等到系統越來越大,你會發現每個 endpoint 命名風格都不一樣, Status Code 亂用,前端不知道何時該 retry,出了 bug 沒有人知道從哪裡看。 這篇帶你系統性地理解 API 設計的三種主流方案,以及在不同情境下如何做出正確選擇。
Section 1:為什麼 API 設計很重要
API 設計是軟體工程中一個容易被輕視的環節。大多數初學者在第一次寫後端時,關注的是「能不能動」, 而不是「設計得好不好」。但 API 是前後端之間的契約——一旦上線,改動就有代價。
設計糟糕的 API
動詞混入 URL、命名不一致、欄位語義不清、難以維護
設計良好的 RESTful API
以資源為核心、HTTP Method 語義清晰、URL 簡潔可預測
API 是你後端的門面。設計糟的 API 就像沒有菜單的餐廳,客人只能靠猜。
好的 API 設計讓前端工程師不需要讀文件就能猜到 endpoint 是什麼。 這種「最少驚喜原則(Principle of Least Surprise)」是 API 設計的核心價值之一。
Section 2:RESTful API 設計原則
REST(Representational State Transfer)不是一個標準,而是一組風格指南。 以下六個核心原則是業界公認的最佳實踐,掌握它們你的 API 就能讓人賞心悅目。
以資源為中心(名詞,不是動詞)
URL 代表的是「資源」,動作由 HTTP Method 表達。不要把動詞塞進 URL——那是 RPC 風格,不是 REST。
HTTP Method 有語義
不同的 HTTP Method 代表不同的操作意圖,正確使用能讓 API 的行為可預測。 冪等性(Idempotent)意指「重複執行相同請求,結果相同」,這對重試機制很重要。
| Method | 用途 | 冪等 | 有 Body |
|---|---|---|---|
| GET | 讀取資源 | ✅ 是 | ❌ 否 |
| POST | 建立資源 | ❌ 否 | ✅ 是 |
| PUT | 全量更新(取代整個資源) | ✅ 是 | ✅ 是 |
| PATCH | 部分更新(只改指定欄位) | ⚠️ 視實作 | ✅ 是 |
| DELETE | 刪除資源 | ✅ 是 | ❌ 通常否 |
Status Code 要正確
最常見的錯誤:所有 response 都回傳 200,然後在 body 裡放 success: false。 這讓監控系統無法正確判斷錯誤率,也讓前端工程師非常困惑。正確使用 HTTP Status Code 是專業度的體現。
401 vs 403 的差別:401 是「我不知道你是誰」,403 是「我知道你是誰,但你沒有權限」。 例如:沒帶 JWT token 是 401;帶了 token 但嘗試刪除別人的資料是 403。
版本控制
API 版本控制讓你能在不破壞舊客戶端的前提下推出新版 API。 常見的版本控制策略有三種:URL 路徑(最直覺)、Header(最乾淨)、Query String(最懶惰)。
為什麼需要版本?行動端 App 用戶可能還在使用三個月前的舊版本,這些用戶仍在呼叫 v1 API。 如果你直接改 v1,這些用戶的 App 就會壞掉。版本控制讓你可以漸進式遷移。
Filter / Sort / Pagination
永遠不要設計「回傳所有資料」的 endpoint,這是資料庫的炸彈。 用 Query Parameters 提供篩選、排序、分頁能力。
回應格式標準化
統一的回應格式讓前端工程師能寫通用的 error handler,而不是每個 endpoint 都要特殊處理。
Section 3:GraphQL — 你問什麼就給什麼
GraphQL 是 Facebook 在 2015 年開源的查詢語言,為了解決 REST 在複雜前端需求下的兩個核心問題:Over-fetching(拿了太多不需要的欄位) 和 Under-fetching(一個頁面需要打多個 API)。
REST 的困境:N+1 查詢問題
GraphQL 用一個 endpoint + 彈性查詢語言解決了這個問題:
GraphQL Schema 定義(後端)
GraphQL 是強型別的。你需要先定義 Schema(資料的形狀),前端只能查詢 Schema 裡有的欄位。 這個強約束同時也是它的優勢——IDE 可以提供完整的自動補全。
React 中使用 GraphQL(Apollo Client)
GraphQL 的缺點
- 學習曲線:需要理解 Schema、Resolver、DataLoader 等概念
- N+1 問題沒有自動消失:Resolver 層仍需用 DataLoader 做 batch 查詢
- 快取困難:REST 可以用 URL 做 HTTP 快取,GraphQL 需要 Apollo Cache 等工具
- 對外 API 不友善:第三方開發者更熟悉 REST
Section 4:tRPC — 前後端型別完全共享
tRPC(TypeScript Remote Procedure Call)是 2021 年興起的方案,專門為 TypeScript 全端專案設計。 它的核心概念很簡單:後端定義 procedure(程序),前端直接呼叫,型別自動推導,零 schema、零 code generation。
用 REST 的時候,你通常需要手動維護 TypeScript 型別或 OpenAPI schema,這很容易讓前後端型別不同步。 GraphQL 需要 code generation(graphql-codegen)才能有型別。 tRPC 直接跳過這些:後端的回傳型別,前端自動就有。
後端定義(Next.js API Routes)
前端使用(完整型別,零配置)
tRPC 的核心優勢
- 型別安全 100%:後端改了回傳欄位,前端立刻報錯,不需要任何 codegen
- 重構友善:rename 一個 procedure,IDE 會幫你找到所有使用到的地方
- 開發速度快:不需要寫 OpenAPI spec、不需要 graphql-codegen
- DX 極佳:後端和前端工程師共享同一個 TypeScript 型別系統
限制:只適合前後端同一個 TypeScript monorepo 的場景。 如果有 iOS App、Android App、第三方合作方,tRPC 就幫不了你了。
Section 5:三種方案全面對比
沒有最好的方案,只有最適合當前情境的方案。以下對比幫助你在做技術選型時有清晰的依據。
| 比較維度 | REST | GraphQL | tRPC |
|---|---|---|---|
| 學習成本 | 低 | 中 | 低(需 TypeScript) |
| 型別安全 | 手動維護 (OpenAPI/Swagger) | Schema 生成 (需 codegen) | 自動推導 (100% 覆蓋) |
| 前後端共用型別 | ❌ | ⚠️ 需 codegen | ✅ 原生支援 |
| 適合微服務 | ✅ | ✅ | ❌ 單一 repo |
| 行動端 / 外部 API | ✅ 最通用 | ✅ | ❌ |
| 效能 | 可能 N+1 (需手動最佳化) | Batch(DataLoader) 需額外設定 | 等同 REST (底層同 HTTP) |
| HTTP 快取 | ✅ 原生支援 | ❌ 需 Apollo | ⚠️ React Query |
| 2026 趨勢 | 主流(穩定) | 下降中 | 上升中 |
GraphQL 的趨勢下降主要原因:複雜度高、學習曲線陡峭、大多數應用其實不需要它的彈性查詢能力。 tRPC 的崛起則是因為 Next.js 生態的成熟,越來越多團隊採用 TypeScript 全端方案。
Section 6:決策指南 — 如何選擇
技術選型沒有對錯,關鍵是理解每個方案的適用情境。用以下決策樹幫助你做出有依據的選擇:
API 技術選型決策樹
選 REST 的情境
- ✓ 有外部 API 消費者
- ✓ 行動端(iOS / Android)
- ✓ 微服務架構
- ✓ 團隊有不熟 TypeScript 的成員
- ✓ 需要 CDN / HTTP 快取
- ✓ 預設選擇(最保險)
選 GraphQL 的情境
- ✓ 複雜的前端資料需求
- ✓ 多個前端(web + mobile)共用同一 API
- ✓ 資料關聯複雜(社交圖譜)
- ✓ 需要即時訂閱(Subscription)
- ✓ 團隊已有 GraphQL 經驗
選 tRPC 的情境
- ✓ Next.js + TypeScript 全端
- ✓ 小到中型團隊
- ✓ 快速迭代的 SaaS 產品
- ✓ 重視 DX 和型別安全
- ✓ 前後端共用型別是關鍵需求
Section 7:REST API 安全性速查
這是後端工程師最容易忽略的部分。功能做好了,但安全沒做到位,一樣是爛的 API。 以下是每個後端 API 都必須考慮的五個安全面向:
Authentication:JWT Bearer Token
Rate Limiting:防止濫用
CORS:只允許你的前端 Domain
Input Validation:永遠不相信用戶輸入
SQL Injection 防範:用 ORM 或 Prepared Statement
安全性核心原則
- 永遠在後端驗證 input(前端驗證只是 UX,不是安全)
- 密碼使用 bcrypt / argon2 雜湊,永遠不要明文儲存
- 敏感操作(刪帳號、改 Email)要求重新輸入密碼確認
- Log 不要記錄密碼、Token、信用卡號等敏感資訊
- HTTPS 是必須的,不是選配