fastify
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFastify Core Knowledge
Fastify 核心知识
Full Reference: See advanced.md for WebSocket authentication, room management, heartbeat patterns, message validation, and Redis scaling.
Deep Knowledge: Usewith technology:mcp__documentation__fetch_docsfor comprehensive documentation.fastify
完整参考:查看 advanced.md 了解 WebSocket 认证、房间管理、心跳模式、消息验证和 Redis 扩容相关内容。
深度知识:调用并指定 technology 为mcp__documentation__fetch_docs即可获取完整文档。fastify
Basic Setup
基础配置
ts
import Fastify from 'fastify';
import cors from '@fastify/cors';
const app = Fastify({ logger: true });
await app.register(cors);
await app.register(userRoutes, { prefix: '/api/users' });
app.listen({ port: 3000, host: '0.0.0.0' });ts
import Fastify from 'fastify';
import cors from '@fastify/cors';
const app = Fastify({ logger: true });
await app.register(cors);
await app.register(userRoutes, { prefix: '/api/users' });
app.listen({ port: 3000, host: '0.0.0.0' });Route with Schema Validation
带 Schema 验证的路由
ts
import { FastifyPluginAsync } from 'fastify';
import { Type, Static } from '@sinclair/typebox';
const UserSchema = Type.Object({
name: Type.String(),
email: Type.String({ format: 'email' }),
});
type User = Static<typeof UserSchema>;
const routes: FastifyPluginAsync = async (app) => {
app.post<{ Body: User }>('/', {
schema: {
body: UserSchema,
response: { 201: UserSchema }
}
}, async (request, reply) => {
const user = await db.users.create(request.body);
reply.status(201).send(user);
});
};ts
import { FastifyPluginAsync } from 'fastify';
import { Type, Static } from '@sinclair/typebox';
const UserSchema = Type.Object({
name: Type.String(),
email: Type.String({ format: 'email' }),
});
type User = Static<typeof UserSchema>;
const routes: FastifyPluginAsync = async (app) => {
app.post<{ Body: User }>('/', {
schema: {
body: UserSchema,
response: { 201: UserSchema }
}
}, async (request, reply) => {
const user = await db.users.create(request.body);
reply.status(201).send(user);
});
};Plugins
插件
ts
import fp from 'fastify-plugin';
// Custom plugin with fastify-plugin
export default fp(async (app) => {
app.decorate('db', db);
app.addHook('onRequest', async (request) => {
request.startTime = Date.now();
});
});
app.register(myPlugin);ts
import fp from 'fastify-plugin';
// 基于 fastify-plugin 实现的自定义插件
export default fp(async (app) => {
app.decorate('db', db);
app.addHook('onRequest', async (request) => {
request.startTime = Date.now();
});
});
app.register(myPlugin);Error Handling
错误处理
ts
import { FastifyError, FastifyReply, FastifyRequest } from 'fastify';
export class AppError extends Error {
constructor(public statusCode: number, message: string) {
super(message);
}
}
app.setErrorHandler((error: FastifyError, request, reply) => {
request.log.error({ err: error }, 'Request error');
if (error.validation) {
return reply.status(400).send({ error: 'Validation failed', details: error.validation });
}
return reply.status(error.statusCode || 500).send({ error: error.message });
});ts
import { FastifyError, FastifyReply, FastifyRequest } from 'fastify';
export class AppError extends Error {
constructor(public statusCode: number, message: string) {
super(message);
}
}
app.setErrorHandler((error: FastifyError, request, reply) => {
request.log.error({ err: error }, 'Request error');
if (error.validation) {
return reply.status(400).send({ error: 'Validation failed', details: error.validation });
}
return reply.status(error.statusCode || 500).send({ error: error.message });
});Health Checks
健康检查
ts
app.get('/health', async () => ({ status: 'healthy' }));
app.get('/ready', async (request, reply) => {
try {
await app.pg.query('SELECT 1');
return { status: 'ready', database: 'connected' };
} catch (error) {
reply.status(503);
return { status: 'not ready' };
}
});ts
app.get('/health', async () => ({ status: 'healthy' }));
app.get('/ready', async (request, reply) => {
try {
await app.pg.query('SELECT 1');
return { status: 'ready', database: 'connected' };
} catch (error) {
reply.status(503);
return { status: 'not ready' };
}
});Testing
测试
ts
import { test } from 'vitest';
import { buildApp } from '../src/app';
test('GET /api/users returns users', async () => {
const app = await buildApp();
const response = await app.inject({
method: 'GET',
url: '/api/users',
});
expect(response.statusCode).toBe(200);
await app.close();
});ts
import { test } from 'vitest';
import { buildApp } from '../src/app';
test('GET /api/users returns users', async () => {
const app = await buildApp();
const response = await app.inject({
method: 'GET',
url: '/api/users',
});
expect(response.statusCode).toBe(200);
await app.close();
});WebSocket Setup
WebSocket 配置
ts
import websocket from '@fastify/websocket';
await app.register(websocket);
app.get('/ws', { websocket: true }, (socket, req) => {
socket.on('message', (data) => {
const message = JSON.parse(data.toString());
handleMessage(socket, message);
});
});ts
import websocket from '@fastify/websocket';
await app.register(websocket);
app.get('/ws', { websocket: true }, (socket, req) => {
socket.on('message', (data) => {
const message = JSON.parse(data.toString());
handleMessage(socket, message);
});
});When NOT to Use This Skill
不适用该技能的场景
- Enterprise Architecture - Use NestJS for DI and modular design
- Simple CRUD APIs - Use Express if performance is not critical
- Edge Runtimes - Use Hono for Cloudflare Workers
- Deno Projects - Use Oak or Fresh instead
- 企业级架构:需要 DI 和模块化设计请使用 NestJS
- 简单 CRUD API:性能要求不高时请使用 Express
- Edge 运行时:Cloudflare Workers 场景请使用 Hono
- Deno 项目:请改用 Oak 或 Fresh
Anti-Patterns
反模式
| Anti-Pattern | Why It's Bad | Correct Approach |
|---|---|---|
| Not using schema validation | Loses performance advantage | Define schemas for routes |
Missing | Encapsulation issues | Use |
Using | Slow, port conflicts | Use |
| Ignoring response schema | Slower serialization | Define response schemas |
| 反模式 | 弊端 | 正确做法 |
|---|---|---|
| 不使用 schema 验证 | 丢失性能优势 | 为路由定义 schema |
未加 | 出现封装问题 | 共享插件使用 |
测试中使用 | 速度慢、端口冲突 | 使用 |
| 忽略响应 schema | 降低序列化速度 | 定义响应 schema |
Quick Troubleshooting
快速故障排查
| Issue | Likely Cause | Solution |
|---|---|---|
| "Cannot call reply.send twice" | Multiple sends | Return after first |
| Plugin not accessible | Missing fastify-plugin | Wrap with |
| Schema not working | Not registered | Add |
| Type errors with schemas | Provider missing | Use |
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| "Cannot call reply.send twice" | 多次调用 send 方法 | 首次调用 |
| 插件无法访问 | 缺少 fastify-plugin 包装 | 用 |
| Schema 不生效 | 未注册 | 在路由配置中添加 |
| Schema 类型报错 | 缺少类型提供者 | 使用 |
Production Checklist
生产环境检查清单
- TypeBox schema validation
- Helmet security headers
- Rate limiting configured
- Structured logging (Pino)
- Request ID tracing
- Custom error handler
- Health/readiness endpoints
- Graceful shutdown
- Database connection pooling
- TypeBox schema 验证
- Helmet 安全头配置
- 限流规则配置
- 结构化日志(Pino)
- 请求 ID 链路追踪
- 自定义错误处理器
- 健康/就绪检查接口
- 优雅停机逻辑
- 数据库连接池配置
Monitoring Metrics
监控指标
| Metric | Target |
|---|---|
| Response time (p99) | < 50ms |
| Error rate (5xx) | < 0.1% |
| Request throughput | > 10k/s |
| 指标 | 目标值 |
|---|---|
| 响应时间(p99) | < 50ms |
| 错误率(5xx) | < 0.1% |
| 请求吞吐量 | > 10k/s |
Reference Documentation
参考文档
- Schema Validation
- Plugins
- Schema 验证
- 插件