关于 api-design-patterns
面向 API 设计者的 REST 与 GraphQL 设计指南,涵盖版本管理、分页、错误处理和服务契约。通过模式示例与实践原则,辅助新建或改造可维护的 API。
主要功能
- 01REST 资源导向设计
- 02版本与弃用策略
- 03分页与错误响应模式
- 04认证、缓存与限流
- 05GraphQL 查询与变更模式
适用场景
- 01从零规划 REST 或 GraphQL API
- 02统一微服务的服务契约
- 03为大型数据集设计分页
- 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
}
}
}
最佳实践摘要
- 一致性:所有端点都遵循统一约定
- 版本管理:从一开始就规划弃用策略
- 文档:使用 OpenAPI/GraphQL 架构,并保持更新
- 错误处理:提供详细、可操作且带有代码的错误消息
- 安全性:始终使用 HTTPS、验证输入并实施速率限制
- 性能:实施缓存、分页和字段选择
- 监控:记录请求 ID,跟踪延迟和错误率
- 向后兼容性:在同一版本中仅进行增量更改
- 测试:契约测试、集成测试和负载测试
- 文档:提供交互式文档(Swagger UI、GraphQL Playground)
应避免的反模式
- 过于繁琐的 API:往返请求过多(使用批处理、GraphQL)
- 过度获取:返回不必要的数据(使用字段选择)
- 获取不足:需要多次调用(使用 includes/embeds)
- 泄露实现细节:在 API 中暴露数据库结构
- 错误消息不佳:错误信息笼统,缺少细节
- 破坏性变更:未进行版本控制就修改现有字段
- 没有速率限制:可能导致资源耗尽
- 缺少文档:端点和参数没有文档说明
- 命名不一致:不同端点使用不同的命名约定
- 忽视 HTTP 语义:错误使用状态码和方法
资源
- REST:Roy Fielding 的论文、RFC 7231(HTTP 语义)
- OpenAPI:https://spec.openapis.org/oas/latest.html
- GraphQL:https://graphql.org/learn/
- HAL:https://stateless.group/hal_specification.html
- JSON:API:https://jsonapi.org/
- RFC 7807:HTTP API 的问题详情
评论
支持 Markdown