REST API架構設計圖

REST API是什麼?完整設計指南:核心原則、最佳實務與實際應用

更新日期:2025 年 5 月 26 日

在現代網路應用開發中,API(Application Programming Interface)扮演著連接不同系統與服務的重要橋樑。而在眾多 API 設計風格中,REST(Representational State Transfer)無疑是最廣泛採用的架構風格之一。從社群媒體平台到電商網站,從行動應用到企業系統,REST API 無處不在。本文將深入探討 REST API 的核心概念、設計原則,以及如何建構高品質、易維護的 API 介面。

REST API 的基本概念與定義

REST(Representational State Transfer)是由 Roy Fielding 在 2000 年的博士論文中提出的軟體架構風格。REST API 是基於 REST 原則設計的網路服務介面,它利用 HTTP 協定的特性來進行資源的操作與狀態轉換。

REST 的核心概念

  • 資源導向:將系統中的所有事物視為資源,每個資源都有唯一的 URI
  • 統一介面:使用標準的 HTTP 方法來操作資源
  • 無狀態性:每個請求都是獨立的,伺服器不保存客戶端狀態
  • 表示層分離:資源的表示與資源本身分離

💡 簡單比喻

想像 REST API 就像是一間圖書館的管理系統。每本書(資源)都有一個獨特的編號(URI),而你可以透過標準的動作(HTTP 方法)來借書、還書、查詢或預約。圖書館員(伺服器)不需要記住你上次借了什麼書,只需要根據你當前的請求來提供服務。

REST vs 其他 API 風格

特性RESTSOAPGraphQL
協定HTTPHTTP/SMTP/TCPHTTP
資料格式JSON/XMLXMLJSON
學習曲線簡單複雜中等
快取支援優秀有限複雜

REST 的六大核心原則

要設計一個真正符合 REST 風格的 API,必須遵循六個核心原則。這些原則不僅定義了 REST 的本質,也是評估 API 設計品質的重要標準。

1

客戶端-伺服器架構 (Client-Server)

將使用者介面與資料儲存分離,提高系統的可攜性和可擴展性。

實際應用:前端應用(React, Vue)透過 API 與後端服務(Node.js, Python)溝通
2

無狀態性 (Stateless)

每個請求都包含所有必要的資訊,伺服器不儲存客戶端的上下文狀態。

實際應用:使用 JWT Token 進行身份驗證,而非依賴 Session
3

可快取性 (Cacheable)

回應應該明確標示是否可以快取,以提高網路效率。

實際應用:設定適當的 Cache-Control、ETag 等 HTTP 標頭
4

統一介面 (Uniform Interface)

透過標準化的介面簡化整體系統架構,提高互動的可見性。

實際應用:使用標準 HTTP 方法(GET, POST, PUT, DELETE)
5

分層系統 (Layered System)

允許在客戶端和伺服器之間加入中介層,如代理伺服器、閘道等。

實際應用:使用負載平衡器、API Gateway、CDN 等中介層
6

按需編碼 (Code on Demand) - 可選

伺服器可以傳送可執行代碼給客戶端來擴展功能。

實際應用:傳送 JavaScript 代碼、插件或小程式

HTTP 方法與狀態碼運用

REST API 的核心是善用 HTTP 協定的語義。不同的 HTTP 方法代表不同的操作意圖,而狀態碼則清楚表達了操作的結果。

HTTP 方法對應 CRUD 操作

HTTP 方法CRUD 操作用途說明幂等性
GETRead讀取資源資料
POSTCreate建立新資源
PUTUpdate完整更新資源
PATCHUpdate部分更新資源可能
DELETEDelete刪除資源

常用 HTTP 狀態碼

2xx 成功狀態

  • 200 OK - 請求成功
  • 201 Created - 資源建立成功
  • 204 No Content - 成功但無回傳內容

4xx 客戶端錯誤

  • 400 Bad Request - 請求格式錯誤
  • 401 Unauthorized - 未授權
  • 404 Not Found - 資源不存在

資源導向的 URL 設計

良好的 URL 設計是 REST API 的核心。URL 應該直觀地表達資源的層次結構和關係,讓開發者能夠輕易理解 API 的用途。

URL 設計原則

  • 使用名詞而非動詞:URL 表示資源,動作由 HTTP 方法表達
  • 複數形式:集合資源使用複數名詞(/users 而非 /user)
  • 階層結構:反映資源之間的關係(/users/123/posts)
  • 一致性:整個 API 保持命名風格一致

URL 設計範例

✅ 良好設計
GET /api/v1/users - 取得所有使用者
GET /api/v1/users/123 - 取得特定使用者
POST /api/v1/users - 建立新使用者
GET /api/v1/users/123/posts - 取得使用者的文章
❌ 不良設計
GET /api/v1/getUsers - 使用動詞
GET /api/v1/user/123 - 使用單數
POST /api/v1/createUser - 動詞重複
GET /api/v1/userPosts/123 - 結構不清晰

查詢參數與過濾

對於複雜的查詢需求,應該使用查詢參數而非在 URL 路徑中包含過多資訊:

GET /api/v1/users?page=2&limit=10 - 分頁
GET /api/v1/posts?author=john&status=published - 過濾
GET /api/v1/products?sort=price&order=desc - 排序
GET /api/v1/users?fields=name,email - 欄位選擇

REST API 設計最佳實務

除了遵循 REST 原則外,還有許多實務經驗和最佳作法可以讓您的 API 更加完善、安全且易於使用。

版本控制策略

URL 路徑版本

/api/v1/users
/api/v2/users

最常見,清楚明確

Header 版本

Accept: application/vnd.
api+json;version=1

保持 URL 簡潔

查詢參數版本

/api/users?version=1

簡單但不夠明顯

錯誤處理與回應格式

一致的錯誤處理格式能讓 API 使用者更容易理解和處理錯誤情況:

標準錯誤回應格式

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "請求資料驗證失敗",
    "details": [
      {
        "field": "email",
        "message": "電子郵件格式不正確"
      }
    ],
    "timestamp": "2025-05-26T10:30:00Z"
  }
}

認證與授權

🔐 JWT Token 認證

  • 無狀態,符合 REST 原則
  • 包含使用者資訊和權限
  • 支援跨域使用
  • 可設定過期時間

🗝️ API Key 認證

  • 簡單易實作
  • 適合伺服器對伺服器
  • 可限制使用頻率
  • 易於撤銷和管理

效能優化技巧

  • 分頁處理:避免一次回傳過多資料
  • 欄位篩選:允許客戶端指定需要的欄位
  • 壓縮回應:使用 Gzip 壓縮減少傳輸量
  • 快取策略:適當設定 Cache-Control 標頭
  • 資料庫優化:避免 N+1 查詢問題

實際開發範例與應用

讓我們透過一個具體的部落格系統範例,來了解如何設計和實作 REST API。這個範例將展示完整的 CRUD 操作和最佳實務。

部落格系統 API 設計

資源結構設計

使用者管理
GET /api/v1/users - 取得使用者列表
GET /api/v1/users/:id - 取得特定使用者
POST /api/v1/users - 建立新使用者
PUT /api/v1/users/:id - 更新使用者
DELETE /api/v1/users/:id - 刪除使用者
文章管理
GET /api/v1/posts - 取得文章列表
GET /api/v1/posts/:id - 取得特定文章
POST /api/v1/posts - 建立新文章
PUT /api/v1/posts/:id - 更新文章
DELETE /api/v1/posts/:id - 刪除文章
評論管理
GET /api/v1/posts/:id/comments - 取得文章評論
POST /api/v1/posts/:id/comments - 新增評論
PUT /api/v1/comments/:id - 更新評論
DELETE /api/v1/comments/:id - 刪除評論

實作範例:Node.js + Express

// 文章相關 API 實作
const express = require('express');
const router = express.Router();

// 取得所有文章
router.get('/posts', async (req, res) => {
  try {
    const { page = 1, limit = 10, author, status } = req.query;
    
    const query = {};
    if (author) query.author = author;
    if (status) query.status = status;
    
    const posts = await Post.find(query)
      .limit(limit * 1)
      .skip((page - 1) * limit)
      .populate('author', 'name email');
    
    const total = await Post.countDocuments(query);
    
    res.json({
      data: posts,
      pagination: {
        current_page: parseInt(page),
        total_pages: Math.ceil(total / limit),
        total_items: total
      }
    });
  } catch (error) {
    res.status(500).json({
      error: {
        code: 'SERVER_ERROR',
        message: '取得文章列表失敗'
      }
    });
  }
});

// 建立新文章
router.post('/posts', authenticate, async (req, res) => {
  try {
    const { title, content, tags } = req.body;
    
    // 資料驗證
    if (!title || !content) {
      return res.status(400).json({
        error: {
          code: 'VALIDATION_ERROR',
          message: '標題和內容為必填欄位'
        }
      });
    }
    
    const post = new Post({
      title,
      content,
      tags,
      author: req.user.id
    });
    
    await post.save();
    
    res.status(201).json({
      data: post,
      message: '文章建立成功'
    });
  } catch (error) {
    res.status(500).json({
      error: {
        code: 'SERVER_ERROR',
        message: '建立文章失敗'
      }
    });
  }
});

回應資料格式標準化

統一回應格式

// 成功回應格式
{
  "success": true,
  "data": {
    "id": 123,
    "title": "REST API 設計指南",
    "content": "...",
    "created_at": "2025-05-26T10:30:00Z"
  },
  "message": "操作成功",
  "timestamp": "2025-05-26T10:30:00Z"
}

// 列表回應格式
{
  "success": true,
  "data": [...],
  "pagination": {
    "current_page": 1,
    "total_pages": 10,
    "total_items": 95,
    "per_page": 10
  },
  "timestamp": "2025-05-26T10:30:00Z"
}

常見問題與解決方案

在實際開發 REST API 時,開發者經常會遇到一些挑戰和疑問。以下整理了最常見的問題及其解決方案。

❓ 複雜查詢如何處理?

當需要執行複雜的查詢操作時,有幾種解決方案:

方案 1: 使用查詢參數組合
GET /api/posts?author=john&category=tech&date_from=2025-01-01
方案 2: 建立專門的搜尋端點
POST /api/posts/search (搜尋條件放在 body)
方案 3: 使用 GraphQL 處理複雜查詢需求

❓ 批次操作如何設計?

REST 原則上每個請求對應一個資源,但實務上可能需要批次操作:

刪除多個項目:
DELETE /api/posts?ids=1,2,3
批次更新:
PATCH /api/posts/batch
批次建立:
POST /api/posts/batch

❓ 檔案上傳如何處理?

檔案上傳在 REST API 中有幾種常見做法:

直接上傳:
POST /api/uploads (multipart/form-data)
分離式上傳:
POST /api/uploads → 回傳檔案 URL
POST /api/posts (包含檔案 URL)

❓ API 限流如何實作?

保護 API 免受濫用的重要機制:

HTTP 標頭:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1643723400
超出限制時:
HTTP 429 Too Many Requests

🎯 REST API 設計檢查清單

設計原則

  • ☑️ 使用名詞而非動詞
  • ☑️ URL 使用複數形式
  • ☑️ 保持 URL 結構一致
  • ☑️ 善用 HTTP 方法語義

實作細節

  • ☑️ 適當的狀態碼回應
  • ☑️ 統一的錯誤處理格式
  • ☑️ API 版本控制策略
  • ☑️ 完整的 API 文檔

總結

REST API 設計是一門藝術,也是一門科學。遵循 REST 原則能夠創建出直觀、可維護、可擴展的 API 介面。從資源導向的 URL 設計到適當的 HTTP 方法運用,從錯誤處理到效能優化,每個細節都影響著 API 的品質和使用者體驗。

記住,好的 API 設計不僅僅是技術問題,更是使用者體驗問題。一個設計良好的 REST API 應該讓開發者能夠輕易理解和使用,同時具備足夠的彈性來應對未來的需求變化。持續學習、實踐和改進,您也能設計出優秀的 REST API。

延伸閱讀

© 2025 一隻河蟹. All rights reserved. | 隱私條款 | 聯絡我們