Communitygithub.com

API 設計模式

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

API 設計模式 是什麼?

這個技能提供了一套全面的 REST API 設計最佳實踐,專為開發者建構一致且易於使用的生產環境 API 而設計。它涵蓋了 API 設計生命週期的所有關鍵方面:從資源命名慣例(使用複數名詞和 kebab-case)和 HTTP 方法語意(如 GET、POST、PUT、PATCH、DELETE)的正確使用,到標準化回應格式(包括成功、錯誤和分頁回應的 JSON 結構)。此技能也詳細說明了進階主題,例如偏移量與游標式分頁的實作策略、使用括號和逗號分隔格式的篩選與排序語法,以及使用 URL 路徑或 Accept 標頭進行 API 版本控制的策略。此外,它也涵蓋了實務性的安全考量,包括基於令牌的驗證、授權模式(資源擁有權和角色基礎控制)、速率限制實施與分層,並針對不同框架(如 TypeScript/Next.js、Python/Django REST Framework 和 Go/net/http)提供了實作範例。其支援的平台不限於特定框架;這些模式普遍適用於任何 RESTful API 的開發,無論是在 Node.js、Python、Go 或其他生態系統中。此技能對於規劃新 API 端點、審查現有 API 合約、新增分頁、篩選或排序功能、實作錯誤處理、規劃 API 版本策略或建置面向公眾或合作夥伴的 API 的開發者或 AI 代理非常有用。

相容平台~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/ECC/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          # 多詞資源使用 kebab-case
/api/v1/orders?status=active  # 使用查詢參數進行篩選
/api/v1/users/123/orders      # 巢狀資源表示擁有權

# 不良
/api/v1/getUsers              # URL 中包含動詞
/api/v1/user                  # 使用單數(應使用複數)
/api/v1/team_members          # URL 中使用 snake_case
/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;  -- 多取得一筆以判斷 has_next
{
  "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

驗證與授權

基於令牌的驗證

# 在 Authorization 標頭中使用 Bearer 令牌
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 遵循命名慣例(複數、kebab-case、無動詞)
  • 使用正確的 HTTP 方法(讀取用 GET、建立用 POST 等)
  • 回傳適當的狀態碼(不全用 200)
  • 使用綱要驗證輸入(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/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

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.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

相關技能