Communitygithub.com

API 設計模式

REST API 設計模式,包括生產環境 API 的資源命名、狀態碼、分頁、篩選、錯誤回應、版本控制和速率限制。在設計或審查 REST 端點、資源名稱、狀態碼、分頁或版本控制時使用。

API 設計模式 是什麼?

此技巧提供了一套全面的 REST API 設計模式與最佳實踐,旨在幫助開發者設計一致且對開發者友善的 API。它涵蓋了資源命名慣例(複數、小寫、短橫線命名法)、URL 結構、HTTP 方法語意(並說明其冪等性與安全性)以及正確的狀態碼使用方式,避免常見錯誤。此外,它還詳細說明了回應格式,包括成功回應、集合分頁(支援偏移量與游標兩種方式)、錯誤回應的標準結構,以及多種語言(TypeScript、Python、Go)的實作範例。此技巧還觸及了身分驗證(Bearer Token 與 API Key)、授權模式、速率限制策略(整合回應標頭與分層限制)以及 API 版本控制策略(強調 URL 路徑版本控制,並提供版本棄用時間表與破壞性/非破壞性變更的區別)。這份指南對於設計、審查或維護公開或合作夥伴 API 的開發者極具價值。支援平台包括但不限於 Next.js (TypeScript)、Django REST Framework (Python) 和 Go net/http。其運作方式是將這些概念組織成可操作的檢查清單和程式碼範例,開發者可直接將其應用於 API 設計與實作工作流程中。

相容平台~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/api-design

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

API 設計模式 是做什麼的?

針對設計一致、對開發者友善的 REST API 的慣例與最佳實務。

何時啟用

  • 設計新的 API 端點
  • 審查現有的 API 合約
  • 加入分頁、篩選或排序功能
  • 為 API 實作錯誤處理
  • 規劃 API 版本控制策略
  • 建置公開或合作夥伴面向的 API

資源設計

URL 結構

# 資源為名詞、複數、小寫、短橫線命名法 (kebab-case)
GET    /api/v1/users
GET    /api/v1/users/:id
POST   /api/v1/users
PUT    /api/v1/users/:id
PATCH  /api/v1/users/:id
DELETE /api/v1/users/:id

# 用於關聯的子資源
GET    /api/v1/users/:id/orders
POST   /api/v1/users/:id/orders

# 不適用於 CRUD 的操作(謹慎使用動詞)
POST   /api/v1/orders/:id/cancel
POST   /api/v1/auth/login
POST   /api/v1/auth/refresh

命名規則

# 良好做法
/api/v1/team-members          # 多詞資源使用短橫線命名法
/api/v1/orders?status=active  # 使用查詢參數進行篩選
/api/v1/users/123/orders      # 巢狀資源表示所有權

# 不良做法
/api/v1/getUsers              # URL 中包含動詞
/api/v1/user                  # 單數(應使用複數)
/api/v1/team_members          # URL 中使用底線命名法
/api/v1/users/123/getOrders   # 巢狀資源中包含動詞

HTTP 方法與狀態碼

方法語意

方法冪等性安全性用途
GET是是取得資源
POST否否建立資源、觸發操作
PUT是否完整取代資源
PATCH否*否部分更新資源
DELETE是否移除資源

*PATCH 可透過適當實作達到冪等性

狀態碼參考

# 成功
200 OK                    — GET, PUT, PATCH(附回應內文)
201 Created               — POST(包含 Location 標頭)
204 No Content            — DELETE, PUT(無回應內文)

# 用戶端錯誤
400 Bad Request           — 驗證失敗、格式錯誤的 JSON
401 Unauthorized          — 缺少或無效的身份驗證
403 Forbidden             — 已驗證但未經授權
404 Not Found             — 資源不存在
409 Conflict              — 重複條目、狀態衝突
422 Unprocessable Entity  — 語意上無效(JSON 有效但資料錯誤)
429 Too Many Requests     — 超過速率限制

# 伺服器錯誤
500 Internal Server Error — 非預期失敗(切勿暴露細節)
502 Bad Gateway           — 上游服務失敗
503 Service Unavailable   — 暫時超載,包含 Retry-After 標頭

常見錯誤

# 不良做法:一律使用 200
{ "status": 200, "success": false, "error": "Not found" }

# 良好做法:語意化使用 HTTP 狀態碼
HTTP/1.1 404 Not Found
{ "error": { "code": "not_found", "message": "User not found" } }

# 不良做法:驗證錯誤使用 500
# 良好做法:使用 400 或 422 並附帶欄位層級細節

# 不良做法:建立的資源使用 200
# 良好做法:使用 201 並包含 Location 標頭
HTTP/1.1 201 Created
Location: /api/v1/users/abc-123

回應格式

成功回應

{
  "data": {
    "id": "abc-123",
    "email": "[email protected]",
    "name": "Alice",
    "created_at": "2025-01-15T10:30:00Z"
  }
}

集合回應(含分頁)

{
  "data": [
    { "id": "abc-123", "name": "Alice" },
    { "id": "def-456", "name": "Bob" }
  ],
  "meta": {
    "total": 142,
    "page": 1,
    "per_page": 20,
    "total_pages": 8
  },
  "links": {
    "self": "/api/v1/users?page=1&per_page=20",
    "next": "/api/v1/users?page=2&per_page=20",
    "last": "/api/v1/users?page=8&per_page=20"
  }
}

錯誤回應

{
  "error": {
    "code": "validation_error",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address",
        "code": "invalid_format"
      },
      {
        "field": "age",
        "message": "Must be between 0 and 150",
        "code": "out_of_range"
      }
    ]
  }
}

回應包裹變體

// 選項 A:使用資料包裹的結構(建議用於公開 API)
interface ApiResponse<T> {
  data: T;
  meta?: PaginationMeta;
  links?: PaginationLinks;
}

interface ApiError {
  error: {
    code: string;
    message: string;
    details?: FieldError[];
  };
}

// 選項 B:扁平回應(更簡單,常用於內部 API)
// 成功:直接回傳資源
// 錯誤:回傳錯誤物件
// 透過 HTTP 狀態碼區分

分頁

偏移量分頁(簡單)

GET /api/v1/users?page=2&per_page=20

# 實作
SELECT * FROM users
ORDER BY created_at DESC
LIMIT 20 OFFSET 20;

優點: 易於實作,支援「跳轉到第 N 頁」 缺點: 處理大量偏移量時效能緩慢(OFFSET 100000),並行插入時不一致

游標分頁(可擴展)

GET /api/v1/users?cursor=eyJpZCI6MTIzfQ&limit=20

# 實作
SELECT * FROM users
WHERE id > :cursor_id
ORDER BY id ASC
LIMIT 21;  -- 多取一筆以判斷是否有下一頁
{
  "data": [...],
  "meta": {
    "has_next": true,
    "next_cursor": "eyJpZCI6MTQzfQ"
  }
}

優點: 無論位置為何,效能一致;並行插入時穩定 缺點: 無法跳轉到任意頁面,遊標不透明

何時使用哪一種

使用案例分頁類型
管理後台、小型資料集(<10K)偏移量
無限滾動、資訊流、大型資料集游標
公開 API游標(預設)搭配偏移量(選擇性)
搜尋結果偏移量(用戶期望頁碼)

篩選、排序與搜尋

篩選

# 簡單相等
GET /api/v1/orders?status=active&customer_id=abc-123

# 比較運算子(使用中括號表示法)
GET /api/v1/products?price[gte]=10&price[lte]=100
GET /api/v1/orders?created_at[after]=2025-01-01

# 多個值(逗號分隔)
GET /api/v1/products?category=electronics,clothing

# 巢狀欄位(點記法)
GET /api/v1/orders?customer.country=US

排序

# 單一欄位(前綴 - 表示降冪)
GET /api/v1/products?sort=-created_at

# 多個欄位(逗號分隔)
GET /api/v1/products?sort=-featured,price,-created_at

全文搜尋

# 搜尋查詢參數
GET /api/v1/products?q=wireless+headphones

# 特定欄位搜尋
GET /api/v1/users?email=alice

稀疏欄位集

# 僅回傳指定欄位(減少負載)
GET /api/v1/users?fields=id,name,email
GET /api/v1/orders?fields=id,total,status&include=customer.name

身分驗證與授權

基於 Token 的驗證

# Authorization 標頭中的 Bearer Token
GET /api/v1/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

# API 金鑰(用於伺服器對伺服器)
GET /api/v1/data
X-API-Key: sk_live_abc123

授權模式

// 資源層級:檢查所有權
app.get("/api/v1/orders/:id", async (req, res) => {
  const order = await Order.findById(req.params.id);
  if (!order) return res.status(404).json({ error: { code: "not_found" } });
  if (order.userId !== req.user.id) return res.status(403).json({ error: { code: "forbidden" } });
  return res.json({ data: order });
});

// 基於角色:檢查權限
app.delete("/api/v1/users/:id", requireRole("admin"), async (req, res) => {
  await User.delete(req.params.id);
  return res.status(204).send();
});

速率限制

標頭

HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000

# 超過限制時
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Try again in 60 seconds."
  }
}

速率限制層級

層級限制時間窗口使用案例
匿名30/分鐘每個 IP公開端點
已驗證100/分鐘每個用戶標準 API 存取
高級1000/分鐘每個 API 金鑰付費 API 方案
內部10000/分鐘每個服務服務對服務

版本控制

URL 路徑版本控制(建議使用)

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

優點: 明確、易於路由、可快取 缺點: 不同版本間 URL 會變更

標頭版本控制

GET /api/users
Accept: application/vnd.myapp.v2+json

優點: URL 整潔 缺點: 較難測試、容易忘記

版本控制策略

1. 從 /api/v1/ 開始——直到需要時才進行版本控制
2. 最多維護 2 個活躍版本(當前 + 前一個)
3. 棄用時間表:
   - 宣布棄用(公開 API 提前 6 個月通知)
   - 加入 Sunset 標頭:Sunset: Sat, 01 Jan 2026 00:00:00 GMT
   - 在日落日期後回傳 410 Gone
4. 非破壞性變更無需新版本:
   - 在回應中新增欄位
   - 新增新的可選查詢參數
   - 新增新的端點
5. 破壞性變更需要新版本:
   - 移除或重新命名欄位
   - 變更欄位類型
   - 變更 URL 結構
   - 變更身分驗證方法

實作模式

TypeScript (Next.js API 路由)

import { z } from "zod";
import { NextRequest, NextResponse } from "next/server";

const createUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100),
});

export async function POST(req: NextRequest) {
  const body = await req.json();
  const parsed = createUserSchema.safeParse(body);

  if (!parsed.success) {
    return NextResponse.json({
      error: {
        code: "validation_error",
        message: "Request validation failed",
        details: parsed.error.issues.map(i => ({
          field: i.path.join("."),
          message: i.message,
          code: i.code,
        })),
      },
    }, { status: 422 });
  }

  const user = await createUser(parsed.data);

  return NextResponse.json(
    { data: user },
    {
      status: 201,
      headers: { Location: `/api/v1/users/${user.id}` },
    },
  );
}

Python (Django REST Framework)

from rest_framework import serializers, viewsets, status
from rest_framework.response import Response

class CreateUserSerializer(serializers.Serializer):
    email = serializers.EmailField()
    name = serializers.CharField(max_length=100)

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "email", "name", "created_at"]

class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated]

    def get_serializer_class(self):
        if self.action == "create":
            return CreateUserSerializer
        return UserSerializer

    def create(self, request):
        serializer = CreateUserSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = UserService.create(**serializer.validated_data)
        return Response(
            {"data": UserSerializer(user).data},
            status=status.HTTP_201_CREATED,
            headers={"Location": f"/api/v1/users/{user.id}"},
        )

Go (net/http)

func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
    var req CreateUserRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        writeError(w, http.StatusBadRequest, "invalid_json", "Invalid request body")
        return
    }

    if err := req.Validate(); err != nil {
        writeError(w, http.StatusUnprocessableEntity, "validation_error", err.Error())
        return
    }

    user, err := h.service.Create(r.Context(), req)
    if err != nil {
        switch {
        case errors.Is(err, domain.ErrEmailTaken):
            writeError(w, http.StatusConflict, "email_taken", "Email already registered")
        default:
            writeError(w, http.StatusInternalServerError, "internal_error", "Internal error")
        }
        return
    }

    w.Header().Set("Location", fmt.Sprintf("/api/v1/users/%s", user.ID))
    writeJSON(w, http.StatusCreated, map[string]any{"data": user})
}

API 設計檢查清單

在發布新的端點之前:

  • 資源 URL 符合命名慣例(複數、短橫線命名法、無動詞)
  • 使用正確的 HTTP 方法(GET 用於讀取,POST 用於建立等)
  • 回傳適當的狀態碼(不要一律使用 200)
  • 輸入已透過 schema 驗證(Zod、Pydantic、Bean Validation)
  • 錯誤回應遵循標準格式,附帶代碼和訊息
  • 清單端點已實作分頁(游標或偏移量)
  • 需要身分驗證(或明確標記為公開)
  • 已檢查授權(用戶只能存取自己的資源)
  • 已設定速率限制
  • 回應不會洩漏內部細節(堆疊追蹤、SQL 錯誤)
  • 與現有端點命名一致(camelCase 對比 snake_case)
  • 已撰寫文件(已更新 OpenAPI/Swagger 規格)

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

相關技能