mcpField
A
api-design-patterns

api-design-patterns

github.com/nickcrew开发6686 次安装19 周前更新
代码仓库

关于 api-design-patterns

面向 API 设计者的 REST 与 GraphQL 设计指南,涵盖版本管理、分页、错误处理和服务契约。通过模式示例与实践原则,辅助新建或改造可维护的 API。

主要功能

  1. 01REST 资源导向设计
  2. 02版本与弃用策略
  3. 03分页与错误响应模式
  4. 04认证、缓存与限流
  5. 05GraphQL 查询与变更模式

适用场景

  1. 01从零规划 REST 或 GraphQL API
  2. 02统一微服务的服务契约
  3. 03为大型数据集设计分页
  4. 04规范错误处理和响应格式

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nickcrew/claude-cortex --skill api-design-patterns

安装后在 Claude Code 中输入/api-design-patterns确认已加载。

附带文件references/design-process.mdvalidation/rubric.yaml

详细介绍

API 设计模式

提供专家指导,帮助使用版本管理、分页、错误处理、身份验证和服务契约等行业标准模式,设计可扩展、易维护的 REST 和 GraphQL API。

何时使用此技能

  • 从头开始设计新的 REST 或 GraphQL API
  • 重构现有 API,以提升可扩展性和一致性
  • 为微服务架构定义服务契约
  • 实施 API 演进的版本管理策略
  • 在各服务之间统一错误处理和响应格式
  • 为大型数据集设计分页
  • 实施 HATEOAS 或超媒体驱动的 API
  • 创建 API 规范(OpenAPI、GraphQL Schema)

快速参考

主题加载参考资料
设计流程skills/api-design-patterns/references/design-process.md

核心原则

1. 面向资源的设计(REST)

URL 表示资源,而非操作:

✓ GET    /users/123
✓ POST   /users
✓ PUT    /users/123
✓ DELETE /users/123

✗ GET    /getUser?id=123
✗ POST   /createUser
✗ POST   /deleteUser

按语义使用 HTTP 方法:

  • GET:检索资源,幂等且可缓存
  • POST:创建资源,非幂等
  • PUT:替换整个资源,幂等
  • PATCH:部分更新,幂等
  • DELETE:删除资源,幂等
2. 一致的命名约定
Resources:        /users, /orders, /products (plural nouns)
Nested:           /users/123/orders
Collections:      /users?status=active&page=2
Sub-resources:    /users/123/settings
Actions (rare):   /users/123/activate (POST)
3. HTTP 状态码

成功:

  • 200 OK:GET、PUT、PATCH 的标准响应
  • 201 Created:资源已创建(POST),返回 Location 标头
  • 202 Accepted:异步处理已启动
  • 204 No Content:操作成功且无响应正文(DELETE)

客户端错误:

  • 400 Bad Request:语法无效或验证失败
  • 401 Unauthorized:需要身份验证或身份验证失败
  • 403 Forbidden:已通过身份验证,但权限不足
  • 404 Not Found:资源不存在
  • 409 Conflict:状态冲突(重复、版本不匹配)
  • 422 Unprocessable Entity:语义验证失败
  • 429 Too Many Requests:超出速率限制

服务器错误:

  • 500 Internal Server Error:服务器发生意外故障
  • 502 Bad Gateway:上游服务故障
  • 503 Service Unavailable:暂时过载或维护中
  • 504 Gateway Timeout:上游超时

版本管理策略

URI 版本管理(最常见)
GET /v1/users/123
GET /v2/users/123

Pros: Clear, easy to route, browser-testable
Cons: URL proliferation, cache fragmentation
When: Public APIs, major breaking changes
标头版本管理
GET /users/123
Accept: application/vnd.myapi.v2+json

Pros: Clean URLs, content negotiation
Cons: Harder to test, caching complexity
When: Internal APIs, minor version differences
查询参数版本管理
GET /users/123?version=2

Pros: Simple, backward compatible
Cons: Pollutes query space, inconsistent
When: Rare, legacy compatibility
弃用标头
Sunset: Sat, 31 Dec 2024 23:59:59 GMT
Deprecation: true
Link: <https://api.example.com/v2/users/123>; rel="successor-version"

分页模式

基于偏移量的分页
GET /users?limit=20&offset=40

Response:
{
  "data": [...],
  "pagination": {
    "limit": 20,
    "offset": 40,
    "total": 1543
  },
  "links": {
    "next": "/users?limit=20&offset=60",
    "prev": "/users?limit=20&offset=20"
  }
}

Pros: Simple, predictable, supports total count
Cons: Inconsistent with concurrent writes, performance degrades
When: Small datasets, stable data, admin UIs
基于游标的分页
GET /users?limit=20&cursor=eyJpZCI6MTIzfQ

Response:
{
  "data": [...],
  "pagination": {
    "next_cursor": "eyJpZCI6MTQzfQ",
    "has_more": true
  },
  "links": {
    "next": "/users?limit=20&cursor=eyJpZCI6MTQzfQ"
  }
}

Pros: Consistent with writes, scalable, efficient
Cons: No total count, can't jump to arbitrary page
When: Large datasets, real-time feeds, infinite scroll
键集分页(Seek 方法)
GET /users?limit=20&after_id=123&created_after=2024-01-01T00:00:00Z

Pros: Most performant, index-friendly
Cons: Requires sortable field, complex queries
When: Very large datasets, time-series data

错误响应格式

标准错误架构
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "code": "INVALID_FORMAT",
        "message": "Email format is invalid"
      },
      {
        "field": "age",
        "code": "OUT_OF_RANGE",
        "message": "Age must be between 18 and 120"
      }
    ],
    "request_id": "req_a3f7c9b2",
    "timestamp": "2024-01-15T10:30:00Z",
    "documentation_url": "https://docs.api.com/errors/VALIDATION_ERROR"
  }
}
错误代码模式
Format: CATEGORY_SPECIFIC_REASON

Authentication:
- AUTH_MISSING_TOKEN
- AUTH_INVALID_TOKEN
- AUTH_EXPIRED_TOKEN

Authorization:
- AUTHZ_INSUFFICIENT_PERMISSIONS
- AUTHZ_RESOURCE_FORBIDDEN

Validation:
- VALIDATION_MISSING_FIELD
- VALIDATION_INVALID_FORMAT
- VALIDATION_OUT_OF_RANGE

Business Logic:
- BUSINESS_DUPLICATE_EMAIL
- BUSINESS_INSUFFICIENT_BALANCE
- BUSINESS_OPERATION_NOT_ALLOWED

System:
- SYSTEM_INTERNAL_ERROR
- SYSTEM_SERVICE_UNAVAILABLE
- SYSTEM_RATE_LIMIT_EXCEEDED

筛选与搜索

用于筛选的查询参数
GET /users?status=active&role=admin&created_after=2024-01-01

GET /users?search=john&fields=name,email

GET /users?sort=-created_at,name  # - prefix for descending
复杂筛选(FIQL/RSQL)
GET /users?filter=status==active;role==admin,role==moderator
               # AND between semicolons, OR between commas

GET /products?filter=price>100;price<500;category==electronics
全文搜索
GET /users?q=john+smith&fields=name,bio,company

Response includes relevance scoring:
{
  "data": [
    {
      "id": 123,
      "name": "John Smith",
      "_score": 0.95
    }
  ]
}

字段选择(稀疏字段集)

GET /users/123?fields=id,name,email

Response:
{
  "id": 123,
  "name": "John Doe",
  "email": "[email protected]"
}

# Nested resources
GET /users/123?fields=id,name,profile(avatar,bio)

Benefits:
- Reduced payload size
- Faster response times
- Lower bandwidth consumption
- Better mobile performance

HATEOAS(超媒体)

HAL(超文本应用语言)
{
  "id": 123,
  "name": "John Doe",
  "email": "[email protected]",
  "_links": {
    "self": { "href": "/users/123" },
    "orders": { "href": "/users/123/orders" },
    "update": { "href": "/users/123", "method": "PUT" },
    "delete": { "href": "/users/123", "method": "DELETE" }
  },
  "_embedded": {
    "recent_orders": [
      {
        "id": 456,
        "total": 99.99,
        "_links": {
          "self": { "href": "/orders/456" }
        }
      }
    ]
  }
}
JSON:API 格式
{
  "data": {
    "type": "users",
    "id": "123",
    "attributes": {
      "name": "John Doe",
      "email": "[email protected]"
    },
    "relationships": {
      "orders": {
        "links": {
          "self": "/users/123/relationships/orders",
          "related": "/users/123/orders"
        }
      }
    },
    "links": {
      "self": "/users/123"
    }
  }
}

速率限制标头

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 742
X-RateLimit-Reset: 1705320000
Retry-After: 3600

# Standard (RFC 6585)
RateLimit-Limit: 1000
RateLimit-Remaining: 742
RateLimit-Reset: 3600

身份验证模式

Bearer Token(OAuth 2.0、JWT)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Pros: Stateless, scalable, standard
Cons: Token size, revocation complexity
When: Modern APIs, microservices
API Key
X-API-Key: ak_live_a3f7c9b2d8e1f4g6h9

Pros: Simple, server-side management
Cons: Less secure, harder to scope
When: Internal services, admin APIs
Basic Auth
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Pros: Simple, built-in browser support
Cons: Credentials in every request
When: Internal tools, development only

幂等性

幂等键(POST)
POST /payments
Idempotency-Key: a3f7c9b2-d8e1-4f6g-h9i0-j1k2l3m4n5o6
Content-Type: application/json

{
  "amount": 100.00,
  "currency": "USD",
  "description": "Payment for order #123"
}

# Server stores key + response for 24 hours
# Duplicate requests return cached response with 200 OK
自然幂等性
PUT /users/123          # Always idempotent
DELETE /users/123       # Idempotent (404 on repeat)
POST /users/123/follow  # Use PUT for idempotency

缓存策略

ETag(条件请求)
# Initial request
GET /users/123
ETag: "a3f7c9b2"

# Subsequent request
GET /users/123
If-None-Match: "a3f7c9b2"

# Response if unchanged:
304 Not Modified
Cache-Control 标头
# Never cache
Cache-Control: no-store

# Cache for 1 hour, revalidate
Cache-Control: max-age=3600, must-revalidate

# Cache forever (immutable)
Cache-Control: public, max-age=31536000, immutable

GraphQL 模式

查询结构
query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
    email
    orders(first: 10) {
      edges {
        node {
          id
          total
          status
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
错误处理
{
  "data": {
    "user": null
  },
  "errors": [
    {
      "message": "User not found",
      "locations": [{ "line": 2, "column": 3 }],
      "path": ["user"],
      "extensions": {
        "code": "NOT_FOUND",
        "userId": "123"
      }
    }
  ]
}
变更模式
mutation CreateUser($input: CreateUserInput!) {
  createUser(input: $input) {
    user {
      id
      name
      email
    }
    errors {
      field
      message
    }
  }
}

最佳实践摘要

  1. 一致性:所有端点都遵循统一约定
  2. 版本管理:从一开始就规划弃用策略
  3. 文档:使用 OpenAPI/GraphQL 架构,并保持更新
  4. 错误处理:提供详细、可操作且带有代码的错误消息
  5. 安全性:始终使用 HTTPS、验证输入并实施速率限制
  6. 性能:实施缓存、分页和字段选择
  7. 监控:记录请求 ID,跟踪延迟和错误率
  8. 向后兼容性:在同一版本中仅进行增量更改
  9. 测试:契约测试、集成测试和负载测试
  10. 文档:提供交互式文档(Swagger UI、GraphQL Playground)

应避免的反模式

  1. 过于繁琐的 API:往返请求过多(使用批处理、GraphQL)
  2. 过度获取:返回不必要的数据(使用字段选择)
  3. 获取不足:需要多次调用(使用 includes/embeds)
  4. 泄露实现细节:在 API 中暴露数据库结构
  5. 错误消息不佳:错误信息笼统,缺少细节
  6. 破坏性变更:未进行版本控制就修改现有字段
  7. 没有速率限制:可能导致资源耗尽
  8. 缺少文档:端点和参数没有文档说明
  9. 命名不一致:不同端点使用不同的命名约定
  10. 忽视 HTTP 语义:错误使用状态码和方法

资源

评论

支持 Markdown