name: api-patterns description: API路由实现模式,包含RLS、Zod验证和错误处理。在创建API路由、实现端点或添加服务器端验证时使用。
API模式技能
目的
引用现有API模式并提供安全、验证的API路由实现的检查表。所有API路由必须使用RLS上下文助手——参见rls-patterns技能。
适用场景
- 创建新API路由
- 实现CRUD端点
- 添加请求/响应验证
- 处理webhooks
- 实现错误处理模式
权威参考(必读)
| 模式 | 位置 | 目的 |
|---|---|---|
| 用户上下文API | docs/patterns/api/user-context-api.md |
用户范围操作 |
| 管理员上下文API | docs/patterns/api/admin-context-api.md |
管理员范围操作 |
| Zod验证 | docs/patterns/api/zod-validation-api.md |
请求/响应验证 |
| Webhook处理器 | docs/patterns/api/webhook-handler.md |
Webhook处理 |
| 奖励内容 | docs/patterns/api/bonus-content-delivery.md |
受保护内容交付 |
停止条件
禁止模式
// 禁止:直接调用Prisma(绕过RLS)
const users = await prisma.user.findMany();
// 必须使用:withUserContext、withAdminContext或withSystemContext
// 禁止:缺少身份验证检查
export async function GET(req: Request) {
return getUserData(); // 没有身份验证检查!
}
// 禁止:未验证的用户输入
const { userId } = await req.json();
// 必须使用Zod模式验证
// 禁止:通用错误响应
return new Response("错误", { status: 500 });
// 必须使用结构化错误响应
正确模式
// 正确:RLS上下文 + 身份验证检查
export async function GET(req: Request) {
const { userId } = await auth();
if (!userId) {
return NextResponse.json({ error: "未授权" }, { status: 401 });
}
const data = await withUserContext(prisma, userId, async (client) => {
return client.user.findUnique({ where: { user_id: userId } });
});
return NextResponse.json(data);
}
// 正确:Zod验证
const schema = z.object({
email: z.string().email(),
name: z.string().min(1),
});
const result = schema.safeParse(body);
if (!result.success) {
return NextResponse.json(
{ error: "验证失败", details: result.error.flatten() },
{ status: 400 },
);
}
API路由检查表
在任何API路由之前:
- [ ] 使用身份验证提供者的
await auth()进行身份验证检查 - [ ] 为未认证用户提供适当的401响应
- [ ] 使用Zod模式进行请求验证
- [ ] RLS上下文包装器(
withUserContext/withAdminContext/withSystemContext) - [ ] 结构化错误响应,状态码适当
- [ ] 请求/响应的TypeScript类型
标准响应模式
成功响应
return NextResponse.json({ data, success: true }, { status: 200 });
错误响应
return NextResponse.json(
{
error: "人类可读的错误消息",
code: "ERROR_CODE",
details: optional_details,
},
{ status: 400 | 401 | 403 | 404 | 500 },
);
状态码
| 代码 | 何时使用 |
|---|---|
| 200 | 成功 |
| 201 | 创建(POST) |
| 400 | 错误请求 / 验证错误 |
| 401 | 未认证 |
| 403 | 禁止(已认证但未授权) |
| 404 | 资源未找到 |
| 500 | 服务器错误 |
API路由模板
import { auth } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";
import { z } from "zod";
import { withUserContext } from "@/lib/rls-helpers";
import { prisma } from "@/lib/prisma";
// 请求验证模式
const RequestSchema = z.object({
// 定义期望字段
});
export async function POST(req: Request) {
try {
// 1. 身份验证
const { userId } = await auth();
if (!userId) {
return NextResponse.json({ error: "未授权" }, { status: 401 });
}
// 2. 解析和验证请求
const body = await req.json();
const result = RequestSchema.safeParse(body);
if (!result.success) {
return NextResponse.json(
{ error: "验证失败", details: result.error.flatten() },
{ status: 400 },
);
}
// 3. 使用RLS上下文执行
const data = await withUserContext(prisma, userId, async (client) => {
return client.resource.create({ data: result.data });
});
// 4. 返回成功响应
return NextResponse.json({ data, success: true }, { status: 201 });
} catch (error) {
console.error("API错误:", error);
return NextResponse.json(
{ error: "内部服务器错误" },
{ status: 500 },
);
}
}
API文档模板
用于记录新端点:
## 端点:POST /api/resource
### 描述
为认证用户创建新资源。
### 认证
必需:会话认证
### 请求体
| 字段 | 类型 | 必需 | 描述 |
| ---- | ------ | ---- | ---------- |
| name | string | 是 | 资源名称 |
| type | string | 否 | 资源类型 |
### 响应
**成功(201)**:
\`\`\`json
{ "data": { "id": 1, "name": "..." }, "success": true }
\`\`\`
**错误(400)**:
\`\`\`json
{ "error": "验证失败", "details": {...} }
\`\`\`
### RLS上下文
使用`withUserContext` - 用户只能访问自己的资源。
相关技能
- rls-patterns: RLS上下文助手使用(所有数据库操作必需)
- security-audit: API安全验证
- testing-patterns: API端点测试