关于 API Design
API Design 是面向 Next.js 应用 API 开发的技能,帮助开发者处理路由设计、验证与安全等环节,并提供具体工作流和示例。
主要功能
- 01RESTful 路由处理模式
- 02使用 Zod 验证请求
- 03身份验证中间件
- 04速率限制与分页
- 05统一错误与 HTTP 状态码
适用场景
- 01规划基于资源的 API 端点
- 02验证请求正文和参数
- 03通过身份验证保护路由
- 04添加分页和速率限制
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jmsktm/ claude-settings --skill api-design安装后在 Claude Code 中输入/api-design确认已加载。
详细介绍
API 设计与集成技能
Next.js 应用中稳健、可扩展 API 的设计与实现综合指南。从 RESTful 端点设计到请求验证、错误处理、身份验证和速率限制,本技能涵盖了生产就绪 API 开发的各个方面。
构建易于使用、文档完善且遵循行业最佳实践的 API。采用恰当的 HTTP 语义、一致的错误响应,以及类型安全的请求和响应处理。
核心工作流
工作流 1:RESTful 路由处理程序
用途: 按照 REST 约定创建组织良好的 API 路由
步骤:
- 规划基于资源的 URL 结构
- 为每种 HTTP 方法创建路由处理程序
- 实现请求验证
- 添加适当的错误处理
- 返回一致的响应格式
实现:
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
try {
const users = await db.users.findMany()
return NextResponse.json({ users })
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch users' },
{ status: 500 }
)
}
}
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const user = await db.users.create({ data: body })
return NextResponse.json({ user }, { status: 201 })
} catch (error) {
return NextResponse.json(
{ error: 'Failed to create user' },
{ status: 400 }
)
}
}
// app/api/users/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const user = await db.users.findUnique({ where: { id: params.id } })
if (!user) {
return NextResponse.json(
{ error: 'User not found' },
{ status: 404 }
)
}
return NextResponse.json({ user })
}
export async function PATCH(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const body = await request.json()
const user = await db.users.update({
where: { id: params.id },
data: body
})
return NextResponse.json({ user })
}
export async function DELETE(
request: NextRequest,
{ params }: { params: { id: string } }
) {
await db.users.delete({ where: { id: params.id } })
return new NextResponse(null, { status: 204 })
}
工作流 2:使用 Zod 验证请求
用途: 进行类型安全的请求验证,并提供详细的错误消息
实现:
import { z } from 'zod'
import { NextRequest, NextResponse } from 'next/server'
const userSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
age: z.number().int().min(18).optional()
})
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const validated = userSchema.parse(body)
const user = await db.users.create({ data: validated })
return NextResponse.json({ user }, { status: 201 })
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Validation failed', issues: error.issues },
{ status: 400 }
)
}
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
)
}
}
工作流 3:身份验证中间件
用途: 通过身份验证检查保护 API 路由
实现:
// lib/auth-middleware.ts
import { NextRequest, NextResponse } from 'next/server'
export async function withAuth(
handler: (req: NextRequest, context: any) => Promise<NextResponse>
) {
return async (req: NextRequest, context: any) => {
const token = req.headers.get('authorization')?.replace('Bearer ', '')
if (!token) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
)
}
try {
const user = await verifyToken(token)
req.user = user
return handler(req, context)
} catch (error) {
return NextResponse.json(
{ error: 'Invalid token' },
{ status: 401 }
)
}
}
}
// app/api/protected/route.ts
export const GET = withAuth(async (request: NextRequest) => {
const user = request.user
return NextResponse.json({ user })
})
工作流 4:速率限制
用途: 防止 API 遭到滥用
实现:
// lib/rate-limit.ts
const rateLimitMap = new Map<string, { count: number; reset: number }>()
export function rateLimit(limit = 100, window = 60000) {
return async (request: NextRequest) => {
const ip = request.ip || 'anonymous'
const now = Date.now()
const record = rateLimitMap.get(ip)
if (!record || now > record.reset) {
rateLimitMap.set(ip, { count: 1, reset: now + window })
return null
}
if (record.count >= limit) {
return NextResponse.json(
{ error: 'Too many requests' },
{ status: 429 }
)
}
record.count++
return null
}
}
// Usage in route
export async function GET(request: NextRequest) {
const limitResponse = await rateLimit(100, 60000)(request)
if (limitResponse) return limitResponse
// Handle request...
}
工作流 5:分页模式
用途: 高效处理大型数据集
实现:
type PaginatedResponse<T> = {
data: T[]
pagination: {
page: number
limit: number
total: number
totalPages: number
hasNext: boolean
hasPrev: boolean
}
}
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams
const page = parseInt(searchParams.get('page') || '1')
const limit = parseInt(searchParams.get('limit') || '10')
const search = searchParams.get('search') || ''
const skip = (page - 1) * limit
const [users, total] = await Promise.all([
db.users.findMany({
where: { name: { contains: search } },
skip,
take: limit
}),
db.users.count({ where: { name: { contains: search } } })
])
const totalPages = Math.ceil(total / limit)
return NextResponse.json({
data: users,
pagination: {
page,
limit,
total,
totalPages,
hasNext: page < totalPages,
hasPrev: page > 1
}
})
}
快速参考
| 操作 | HTTP 方法 | URL 模式 |
|---|---|---|
| 列出资源 | GET | /api/resources |
| 获取单个资源 | GET | /api/resources/:id |
| 创建 | POST | /api/resources |
| 更新 | PATCH/PUT | /api/resources/:id |
| 删除 | DELETE | /api/resources/:id |
| 执行操作 | POST | /api/resources/:id/action |
HTTP 状态码
成功状态码
200 OK- GET、PUT、PATCH 请求成功201 Created- POST 请求成功(资源已创建)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- 意外错误503 Service Unavailable- 暂时不可用
错误响应格式
type ErrorResponse = {
error: string // Human-readable message
code?: string // Machine-readable code
details?: Record<string, any> // Additional context
timestamp?: string
}
// Usage
return NextResponse.json(
{
error: 'Validation failed',
code: 'VALIDATION_ERROR',
details: { field: 'email', reason: 'Invalid format' },
timestamp: new Date().toISOString()
},
{ status: 400 }
)
CORS 配置
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('Access-Control-Allow-Origin', '*')
response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')
if (request.method === 'OPTIONS') {
return new NextResponse(null, { status: 200, headers: response.headers })
}
return response
}
export const config = {
matcher: '/api/:path*'
}
最佳实践
- 使用 HTTP 语义: 使用正确的状态码(创建时用 201,删除时用 204)
- 保持响应格式一致: 始终返回
{ data }或{ error, code } - 验证所有内容: 使用 Zod 验证请求正文、查询和参数
- 妥善处理错误: 切勿向客户端暴露内部错误
- 记录 API 文档: 使用 OpenAPI/Swagger 编写文档
- 对 API 进行版本控制: 对不兼容变更使用 /api/v1/
- 对列表分页: 始终对列表端点进行分页
- 使用 CORS: 为客户端请求正确配置
- 记录请求日志: 记录所有 API 请求以便调试
- 限制速率: 防止遭到滥用
常见模式
健康检查端点
// app/api/health/route.ts
export async function GET() {
return NextResponse.json({
status: 'ok',
timestamp: new Date().toISOString(),
version: process.env.APP_VERSION
})
}
文件上传
export async function POST(request: NextRequest) {
const formData = await request.formData()
const file = formData.get('file') as File
if (!file) {
return NextResponse.json(
{ error: 'No file provided' },
{ status: 400 }
)
}
const allowedTypes = ['image/jpeg', 'image/png', 'image/webp']
if (!allowedTypes.includes(file.type)) {
return NextResponse.json(
{ error: 'Invalid file type' },
{ status: 400 }
)
}
const url = await uploadFile(file)
return NextResponse.json({ url }, { status: 201 })
}
Webhook 处理程序
export async function POST(request: NextRequest) {
const signature = request.headers.get('x-webhook-signature')
const body = await request.text()
const isValid = verifyWebhookSignature(body, signature)
if (!isValid) {
return NextResponse.json(
{ error: 'Invalid signature' },
{ status: 401 }
)
}
const event = JSON.parse(body)
await processWebhookEvent(event)
return NextResponse.json({ received: true })
}
依赖项
# Validation
npm install zod
# Rate limiting
npm install @upstash/redis @upstash/ratelimit
# API documentation
npm install swagger-ui-react swagger-jsdoc
错误处理
- 400 Bad Request: 输入无效、验证错误
- 401 Unauthorized: 缺少身份验证信息或身份验证无效
- 403 Forbidden: 身份验证有效,但权限不足
- 404 Not Found: 资源不存在
- 409 Conflict: 资源已存在或状态冲突
- 422 Unprocessable: 语法有效,但存在语义错误
- 429 Too Many Requests: 超出速率限制
- 500 Internal Error: 服务器端故障
性能提示
- 为查询字段创建数据库索引
- 对大型数据集实现基于游标的分页
- 使用 Redis 或 SWR 缓存频繁读取的数据
- 使用数据库连接池
- 通过选择字段缩减负载大小
- 使用 gzip 压缩响应
何时使用此技能
在以下情况下调用此技能:
- 创建新的 API 端点
- 实现请求验证
- 设计 API 架构
- 添加身份验证/授权
- 处理文件上传
- 实现 Webhook
- 设置 CORS
- 添加速率限制
- 调试 API 错误
- 优化 API 性能
评论
支持 Markdown