mcpField
A
api-design

api-design

github.com/scientiacapital开发28104 次安装5 周前更新
代码仓库

关于 api-design

api-design 是一项用于设计一致、易维护 REST API 的技能,面向 API 开发者,涵盖端点规范、错误处理、分页、版本管理与文档,并提供主题参考文件。

主要功能

  1. 01REST 资源与 HTTP 方法规范
  2. 02统一错误响应格式
  3. 03游标与偏移分页
  4. 04筛选、排序与速率限制
  5. 05API 版本管理与文档指南

适用场景

  1. 01为新 API 设计端点
  2. 02统一错误与分页行为
  3. 03规划破坏性变更和 API 版本

安装

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

$npx skills add https://github.com/scientiacapital/skills --skill api-design

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

config.json
reference/
checklist.md
documentation.md
error-handling.md
filtering-sorting.md
pagination.md
rate-limiting.md
rest-patterns.md
versioning.md

详细介绍

全面的 API 设计技能,涵盖 RESTful 约定、错误处理、分页、版本控制和文档编写。专注于构建一致、直观且易于维护的 API。

优秀的 API 设计能让正确的做法变得简单,让错误的做法变得困难。这项技能可帮助你创建易于使用和维护的 API。

<quick_start> 资源命名: 使用名词、复数、小写字母和连字符(/users、/blog-posts)

HTTP 方法: GET(读取)、POST(创建)、PUT(替换)、PATCH(更新)、DELETE(移除)

状态码: 200 OK、201 Created、204 No Content、400 Bad Request、401 Unauthorized、403 Forbidden、404 Not Found、429 Rate Limited

分页: 实时数据优先使用基于游标的分页;使用 ?limit=20&cursor=xxx

版本控制: URL 路径(/api/v1/)是最清晰的方式 </quick_start>

<success_criteria> API 设计成功的标准:

  • 资源使用复数名词,且命名一致
  • HTTP 方法符合语义(GET=读取、POST=创建等)
  • 错误响应格式统一,包含 code、message、details、requestId
  • 已实现分页(基于游标或偏移量)
  • 包含速率限制标头(X-RateLimit-Limit、Remaining、Reset)
  • 在需要进行破坏性变更之前定义版本控制策略 </success_criteria>

<core_principles>

API 设计原则

  1. 一致性 - 各处采用相同模式(命名、错误、分页)
  2. 可预测性 - 开发者能够推测功能的工作方式
  3. 简洁性 - 简单场景应易于处理,同时支持复杂场景
  4. 向后兼容性 - 不破坏现有客户端
  5. 自说明性 - 命名清晰,错误消息有帮助 </core_principles>

<rest_basics>

RESTful 约定

资源命名
# GOOD: Nouns, plural, lowercase, hyphenated
GET    /users
GET    /users/{id}
GET    /users/{id}/posts
GET    /blog-posts
GET    /api/v1/user-preferences

# BAD: Verbs, singular, mixed case, underscores
GET    /getUser
GET    /user/{id}
GET    /User/{id}/getPosts
GET    /blog_posts
HTTP 方法
方法用途幂等安全请求体
GET读取资源是是否
POST创建资源否否是
PUT替换资源是否是
PATCH部分更新否*否是
DELETE移除资源是否否

*如果应用相同的补丁,PATCH 就是幂等的。

CRUD 操作
# Collection operations
GET    /users           # List all users
POST   /users           # Create a user

# Single resource operations
GET    /users/{id}      # Get one user
PUT    /users/{id}      # Replace user
PATCH  /users/{id}      # Update user fields
DELETE /users/{id}      # Delete user

# Nested resources
GET    /users/{id}/posts       # User's posts
POST   /users/{id}/posts       # Create post for user
GET    /posts/{id}/comments    # Post's comments
操作(非 CRUD 操作)
# When you need actions, use verbs as sub-resources
POST   /users/{id}/activate
POST   /users/{id}/deactivate
POST   /orders/{id}/cancel
POST   /invoices/{id}/send
POST   /auth/login
POST   /auth/logout
POST   /auth/refresh
状态码
代码含义使用时机
200OKGET、PUT、PATCH 成功
201Created成功创建资源的 POST 请求
204No ContentDELETE 成功
400Bad Request输入无效、验证错误
401Unauthorized缺少或无效的身份验证
403Forbidden已通过身份验证,但未获授权
404Not Found资源不存在
409Conflict重复、状态冲突
422Unprocessable验证失败(可替代 400)
429Too Many Requests请求过多,已触发速率限制
500Server Error意外的服务器错误
</rest_basics>

<error_handling>

错误响应

统一的错误格式
// Standard error response
interface ErrorResponse {
  error: {
    code: string;           // Machine-readable code
    message: string;        // Human-readable message
    details?: ErrorDetail[]; // Field-level errors
    requestId?: string;     // For support/debugging
  };
}

interface ErrorDetail {
  field: string;
  message: string;
  code: string;
}
示例
// 400 Bad Request - Validation error
{
  "error": {
    "code": "validation_error",
    "message": "Invalid request parameters",
    "details": [
      { "field": "email", "message": "Invalid email format", "code": "invalid_format" },
      { "field": "age", "message": "Must be at least 13", "code": "min_value" }
    ],
    "requestId": "req_abc123"
  }
}

// 401 Unauthorized
{
  "error": {
    "code": "unauthorized",
    "message": "Invalid or expired authentication token",
    "requestId": "req_abc123"
  }
}

// 403 Forbidden
{
  "error": {
    "code": "forbidden",
    "message": "You don't have permission to access this resource",
    "requestId": "req_abc123"
  }
}

// 404 Not Found
{
  "error": {
    "code": "not_found",
    "message": "User not found",
    "requestId": "req_abc123"
  }
}

// 429 Rate Limited
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please retry after 60 seconds",
    "requestId": "req_abc123"
  }
}
实现
// Error class
class ApiError extends Error {
  constructor(
    public statusCode: number,
    public code: string,
    message: string,
    public details?: ErrorDetail[]
  ) {
    super(message);
  }
}

// Error handler middleware
function errorHandler(error: Error, req: Request, res: Response) {
  const requestId = req.headers['x-request-id'] || crypto.randomUUID();

  if (error instanceof ApiError) {
    return res.status(error.statusCode).json({
      error: {
        code: error.code,
        message: error.message,
        details: error.details,
        requestId,
      },
    });
  }

  // Log unexpected errors
  logger.error('Unexpected error', { error, requestId });

  // Don't expose internal details
  return res.status(500).json({
    error: {
      code: 'internal_error',
      message: 'An unexpected error occurred',
      requestId,
    },
  });
}

</error_handling>

## 分页
基于游标(推荐)
// Request
GET /posts?limit=20&cursor=eyJpZCI6MTAwfQ

// Response
{
  "data": [...],
  "pagination": {
    "hasMore": true,
    "nextCursor": "eyJpZCI6MTIwfQ",
    "prevCursor": "eyJpZCI6MTAwfQ"
  }
}

优点: 结果一致,可处理实时数据 缺点: 无法跳转到第 N 页

基于偏移量
// Request
GET /posts?page=2&limit=20
// or
GET /posts?offset=20&limit=20

// Response
{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 20,
    "total": 150,
    "totalPages": 8
  }
}

优点: 可跳转到任意页 缺点: 实时数据下结果不一致,在大型表上速度较慢

实现(游标)
// Encode/decode cursor
function encodeCursor(data: object): string {
  return Buffer.from(JSON.stringify(data)).toString('base64url');
}

function decodeCursor(cursor: string): object {
  return JSON.parse(Buffer.from(cursor, 'base64url').toString());
}

// Query with cursor
async function getPosts(limit: number, cursor?: string) {
  const where: any = {};

  if (cursor) {
    const { id } = decodeCursor(cursor);
    where.id = { lt: id };
  }

  const posts = await db.post.findMany({
    where,
    orderBy: { id: 'desc' },
    take: limit + 1, // Fetch one extra to check hasMore
  });

  const hasMore = posts.length > limit;
  const data = hasMore ? posts.slice(0, -1) : posts;

  return {
    data,
    pagination: {
      hasMore,
      nextCursor: hasMore ? encodeCursor({ id: data[data.length - 1].id }) : null,
    },
  };
}
## 筛选与排序

使用查询参数:?status=active、?sort=-created_at(前缀 - 表示降序)、?fields=id,name,email。使用 Zod schema 验证,并根据解析后的筛选条件构建 Prisma where 子句。

完整的查询参数模式和实现方式,请参阅 reference/filtering-sorting.md。

## API 版本控制
URL 路径版本控制(推荐)
GET /api/v1/users
GET /api/v2/users

优点: 清晰、易于理解 缺点: 需要更多维护

标头版本控制
GET /api/users
Accept: application/vnd.api+json; version=2

优点: URL 简洁 缺点: 不明显,测试较困难

### 何时创建新版本

在以下情况下创建新版本:

  • 从响应中移除字段
  • 更改字段类型或格式
  • 移除端点
  • 更改身份验证

在以下情况下无需创建新版本:

  • 添加新的可选字段
  • 添加新的端点
  • 添加新的可选参数
  • 修复错误

<rate_limiting>

速率限制

包含以下标头:X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset。超出限制时返回 429,并附带 Retry-After。使用滑动窗口算法(例如 @upstash/ratelimit)。

层级定义和实现请参阅 reference/rate-limiting.md。 </rate_limiting>

如需了解详细模式,请加载相应的参考资料:
主题参考文件加载时机
REST 模式reference/rest-patterns.md设计端点时
错误处理reference/error-handling.md编写错误响应时
分页reference/pagination.md设计列表端点时
筛选与排序reference/filtering-sorting.md设计查询参数时
速率限制reference/rate-limiting.md配置限流时
版本控制reference/versioning.md演进 API 时
文档reference/documentation.md编写 OpenAPI 规范和文档时
检查清单reference/checklist.md发布前验证时

加载方式: 请求特定主题,或检查上下文是否有所提示。

写入结果旁路文件

最后一步,将内容写入 ~/.claude/skill-analytics/last-outcome-api-design.json:

{"ts":"[UTC ISO8601]","skill":"api-design","version":"1.0.0","variant":"default",
 "status":"[success|partial|error]","runtime_ms":[estimated ms from start],
 "metrics":{"endpoints_designed":[n],"patterns_applied":[n]},
 "error":null,"session_id":"[YYYY-MM-DD]"}

如果某些阶段失败但已生成结果,请使用状态 "partial"。只有在未生成任何输出时才使用 "error"。

评论

支持 Markdown