Communitygithub.com

API设计模式

REST API设计模式,涵盖资源命名、状态码、分页、过滤、错误响应、版本控制和限流等生产级API最佳实践。在设计或审查REST端点、资源命名、状态码、分页或版本控制时使用。

API设计模式 是什么?

本技能提供了一套全面的REST API设计指南,专注于构建一致、开发者友好的生产级API。它涵盖了资源命名规范(如URL中使用小写kebab-case、复数形式、避免动词)、HTTP方法语义和恰当的状态码选择(例如,资源创建返回201,数据返回200,错误使用4xx/5xx),以及标准化的成功、错误和分页响应格式。 该技能深入讲解了实用模式,包括基于偏移量(Offset)和基于游标(Cursor)的分页策略及其各自的优劣势、过滤与排序操作的查询参数语法、令牌认证与API密钥授权、基于IP或API密钥的多层级限流,以及URL路径版本控制和通过自描述版本号(如 `/api/v2/`)进行优雅弃用的最佳实践。 为了在Claude Code、Cursor和Codex等AI代理工具中工作,该技能提供了可直接实施的代码示例,覆盖TypeScript(使用Zod进行验证)、Python(Django REST Framework)和Go(net/http)。它还包括一个在发布新端点前可用的简明清单,确保团队遵循这些指南,从而在项目或公共API中保持一致性并减少错误。

兼容平台~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 vs 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.

相关技能