mcpField
R
rest-api

rest-api

github.com/claude-dev-suite开发4647 次安装6 天前更新
代码仓库

关于 rest-api

面向 REST API 设计与运维的开发参考技能,涵盖资源约定、状态码,以及验证、分页和安全等生产实践。

主要功能

  1. 01资源命名与 HTTP 方法
  2. 02状态码和响应格式
  3. 03查询参数与分页
  4. 04验证、安全和 API 版本管理

适用场景

  1. 01设计一致的 REST 端点
  2. 02规划分页和 API 版本
  3. 03诊断 HTTP 错误及 API 问题

MCP 相关

该技能提及可使用 MCP 文档工具获取更全面的 REST API 文档。

安装

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

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill rest-api

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

附带文件quick-ref/conventions.mdquick-ref/error-handling.md

详细介绍

REST API 核心知识

深入了解:使用 mcp__documentation__fetch_docs,并指定技术:rest-api,获取完整文档。

资源命名

# Collections (plural nouns)
GET    /users              # List users
POST   /users              # Create user
GET    /users/{id}         # Get user
PUT    /users/{id}         # Update user
DELETE /users/{id}         # Delete user

# Nested resources
GET    /users/{id}/posts   # User's posts
POST   /users/{id}/posts   # Create user's post

# Avoid verbs in URLs
❌ GET /getUsers
❌ POST /createUser
✅ GET /users
✅ POST /users

HTTP 方法

方法用途幂等
GET读取资源是
POST创建资源否
PUT替换资源是
PATCH部分更新是
DELETE删除资源是

状态码

代码含义使用场景
200成功GET/PUT/PATCH 成功
201已创建POST 成功
204无内容DELETE 成功
400错误请求验证错误
401未授权缺少或无效的身份验证信息
403禁止访问无权限
404未找到资源不存在
409冲突重复或冲突
422无法处理语义错误
500服务器错误内部错误

响应格式

// Success
{
  "data": { "id": 1, "name": "John" },
  "meta": { "timestamp": "2024-01-15T10:00:00Z" }
}

// Collection
{
  "data": [...],
  "meta": { "total": 100, "page": 1, "limit": 20 }
}

// Error
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Email is required",
    "details": [{ "field": "email", "message": "Required" }]
  }
}

查询参数

GET /users?status=active&sort=-createdAt&page=1&limit=20
GET /users?fields=id,name,email
GET /users?include=posts,profile
GET /users?filter[age][gte]=18

不适用此技能的场景

  • GraphQL API 设计(使用 graphql 技能)
  • tRPC 类型安全 API(使用 trpc 技能)
  • OpenAPI 规范编写(使用 openapi 技能)
  • 需要 WebSockets 或 SSE 的实时 API
  • 需要复杂嵌套查询的 API(可考虑 GraphQL)

反模式

反模式问题解决方案
在 URL 中使用动词(/getUser、/createOrder)不符合 REST 风格,违反资源命名规则对名词使用 HTTP 方法(GET /users、POST /orders)
错误时返回 200具有误导性,破坏 HTTP 语义使用适当的 4xx/5xx 状态码
不对 API 进行版本管理破坏性变更会影响所有客户端使用 URL 或请求头版本管理(/v1/、/v2/)
直接暴露数据库 ID存在安全风险,泄露实现细节使用 UUID 或不透明标识符
大型集合不进行分页性能问题、超时实现游标分页或偏移分页
忽略 HTTP 缓存头性能较差,产生不必要的负载使用 ETag、Cache-Control、Last-Modified
对会改变状态的操作使用 GET存在安全风险,违反 REST 原则使用 POST、PUT、PATCH、DELETE
响应格式不一致令客户端困惑,导致集成问题统一使用 JSON 信封格式
未设置速率限制API 滥用、资源耗尽实现速率限制,并返回 429 响应

快速故障排查

问题可能原因解决方案
401 Unauthorized缺少或无效的身份验证令牌检查 Authorization 请求头,验证令牌
403 Forbidden身份验证有效,但权限不足检查用户角色,验证访问控制
404 Not Found资源不存在或路径错误验证端点 URL,检查资源 ID
409 Conflict资源已存在或状态冲突检查唯一性约束,处理幂等性
422 Unprocessable Entity验证失败检查请求正文,依据架构进行验证
429 Too Many Requests超出速率限制实现退避机制,检查速率限制请求头
500 Internal Server Error服务端错误或崩溃检查服务器日志,添加错误处理
CORS 错误缺少 CORS 请求头配置 CORS 中间件并设置允许的来源
API 响应缓慢未分页、N+1 查询添加分页,优化数据库查询

生产环境就绪

安全配置
// Input validation and sanitization
import { z } from 'zod';

const CreateUserSchema = z.object({
  name: z.string().min(1).max(100).trim(),
  email: z.string().email().toLowerCase(),
  age: z.number().int().min(0).max(150).optional(),
});

// Validate request body
app.post('/users', async (req, res) => {
  const result = CreateUserSchema.safeParse(req.body);
  if (!result.success) {
    return res.status(400).json({
      error: { code: 'VALIDATION_ERROR', details: result.error.issues },
    });
  }
  // Use result.data (validated and transformed)
});

// SQL injection prevention - always use parameterized queries
// NEVER: `SELECT * FROM users WHERE id = '${userId}'`
// GOOD: Use ORM or prepared statements
速率限制
import rateLimit from 'express-rate-limit';

// Different limits for different endpoints
const standardLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100,
  standardHeaders: true,
  message: { error: { code: 'RATE_LIMIT_EXCEEDED' } },
});

const authLimiter = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 5, // Strict for auth endpoints
  skipSuccessfulRequests: true,
});

app.use('/api', standardLimiter);
app.use('/api/auth/login', authLimiter);
API 版本管理
// URL versioning (recommended for breaking changes)
app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);

// Header versioning (for minor versions)
app.use('/api', (req, res, next) => {
  const version = req.headers['api-version'] || '1.0';
  req.apiVersion = version;
  next();
});

// Sunset header for deprecated endpoints
app.get('/api/v1/legacy', (req, res) => {
  res.set('Sunset', 'Sat, 01 Jun 2025 00:00:00 GMT');
  res.set('Deprecation', 'true');
  // ... handle request
});
分页
// Cursor-based pagination (recommended for large datasets)
interface PaginatedResponse<T> {
  data: T[];
  meta: {
    nextCursor: string | null;
    hasMore: boolean;
  };
}

app.get('/users', async (req, res) => {
  const cursor = req.query.cursor as string | undefined;
  const limit = Math.min(parseInt(req.query.limit as string) || 20, 100);

  const users = await db.users.findMany({
    take: limit + 1, // Fetch one extra to check if there's more
    cursor: cursor ? { id: cursor } : undefined,
    orderBy: { createdAt: 'desc' },
  });

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

  res.json({
    data,
    meta: {
      nextCursor: hasMore ? data[data.length - 1].id : null,
      hasMore,
    },
  });
});
错误处理
// Consistent error response format
interface APIError {
  error: {
    code: string;
    message: string;
    details?: unknown;
    requestId?: string;
  };
}

// Global error handler
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  const requestId = req.headers['x-request-id'] as string;

  // Log error with context
  logger.error({
    err,
    requestId,
    path: req.path,
    method: req.method,
  });

  // Don't leak internal errors
  const statusCode = err instanceof HTTPError ? err.statusCode : 500;
  const message = statusCode === 500 ? 'Internal Server Error' : err.message;

  res.status(statusCode).json({
    error: {
      code: err.code || 'INTERNAL_ERROR',
      message,
      requestId,
    },
  });
});
监控指标
指标告警阈值
请求延迟 p99> 500ms
错误率(4xx)> 5%
错误率(5xx)> 1%
速率限制触发次数> 100/min
请求大小> 10MB
CORS 配置
import cors from 'cors';

const corsOptions = {
  origin: (origin, callback) => {
    const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [];
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-ID'],
  credentials: true,
  maxAge: 86400, // 24 hours
};

app.use(cors(corsOptions));
请求/响应日志记录
import pino from 'pino-http';

app.use(pino({
  redact: ['req.headers.authorization', 'req.body.password'],
  serializers: {
    req: (req) => ({
      method: req.method,
      url: req.url,
      query: req.query,
    }),
    res: (res) => ({
      statusCode: res.statusCode,
    }),
  },
}));
检查清单
  • 所有端点均进行输入验证
  • 已配置速率限制
  • 已正确限制 CORS
  • API 版本控制策略
  • 基于游标的分页
  • 统一的错误格式
  • 请求 ID 跟踪
  • 结构化日志记录
  • URL 中不包含敏感数据
  • 已配置请求正文大小限制
  • 超时处理
  • 健康检查端点

参考文档

评论

支持 Markdown