集成速查表
这是一个快速参考指南,展示如何在 Vafast 中集成常用的库和工具。
数据库
Prisma
typescript
import { defineRoute, defineRoutes, Type } from 'vafast'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/users',
handler: async () => {
const users = await prisma.user.findMany()
return { users }
}
}),
defineRoute({
method: 'POST',
path: '/users',
schema: {
body: Type.Object({
name: Type.String(),
email: Type.String({ format: 'email' })
})
},
handler: async ({ body }) => {
const user = await prisma.user.create({
data: body
})
return { user }
}
})
])Drizzle
typescript
import { defineRoute, defineRoutes } from 'vafast'
import { drizzle } from 'drizzle-orm/better-sqlite3'
import Database from 'better-sqlite3'
import { users } from './schema'
const db = drizzle(new Database('sqlite.db'))
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/users',
handler: async () => {
const allUsers = await db.select().from(users)
return { users: allUsers }
}
})
])MongoDB
typescript
import { defineRoute, defineRoutes } from 'vafast'
import { MongoClient } from 'mongodb'
const client = new MongoClient('mongodb://localhost:27017')
const db = client.db('myapp')
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/users',
handler: async () => {
const users = await db.collection('users').find({}).toArray()
return { users }
}
})
])认证
JWT
typescript
import { Server, defineRoute, defineRoutes, Type } from 'vafast'
import { jwt } from '@vafast/jwt'
const routes = defineRoutes([
defineRoute({
method: 'POST',
path: '/login',
schema: {
body: Type.Object({
username: Type.String(),
password: Type.String()
})
},
handler: async ({ body }) => {
const token = await jwt.sign(body, { expiresIn: '1h' })
return { token }
}
})
])
const server = new Server(routes)
server.useGlobalMiddleware(jwt({
secret: process.env.JWT_SECRET
}))Better Auth
typescript
import { defineRoute, defineRoutes } from 'vafast'
import { BetterAuth } from 'better-auth'
import { VafastAdapter } from 'better-auth/adapters/vafast'
const auth = new BetterAuth({
adapter: VafastAdapter({
// 配置选项
})
})
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/profile',
handler: async ({ request }) => {
const session = await auth.api.getSession(request)
return { user: session?.user }
}
})
])中间件
CORS
typescript
import { Server, defineRoute, defineRoutes } from 'vafast'
import { cors } from '@vafast/cors'
const routes = defineRoutes([
// 路由定义
])
const server = new Server(routes)
server.useGlobalMiddleware(cors({
origin: ['http://localhost:3000'],
credentials: true
}))Helmet
typescript
import { Server } from 'vafast'
import { helmet } from '@vafast/helmet'
const server = new Server(routes)
server.useGlobalMiddleware(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"]
}
}
}))Rate Limiting
typescript
import { Server } from 'vafast'
import { rateLimit } from '@vafast/rate-limit'
const server = new Server(routes)
server.useGlobalMiddleware(rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100 // 限制每个IP 15分钟内最多100个请求
}))监控和日志
OpenTelemetry
typescript
import { Server } from 'vafast'
import { opentelemetry } from '@vafast/opentelemetry'
const server = new Server(routes)
server.useGlobalMiddleware(opentelemetry({
serviceName: 'my-vafast-app',
tracing: {
enabled: true,
exporter: {
type: 'otlp',
endpoint: 'http://localhost:4317'
}
}
}))Server Timing
typescript
import { Server } from 'vafast'
import { serverTiming } from '@vafast/server-timing'
const server = new Server(routes)
server.useGlobalMiddleware(serverTiming())文件处理
文件上传
文件上传推荐使用 POST(创建新资源)或 PUT(替换指定资源)。
typescript
import { defineRoute, defineRoutes, parseFile, parseFormData, err } from 'vafast'
import { writeFile } from 'node:fs/promises'
const routes = defineRoutes([
// 方式1:POST 上传新文件(最常用)
// 服务器决定存储位置,返回文件 ID
defineRoute({
method: 'POST',
path: '/files',
handler: async ({ req }) => {
const file = await parseFile(req)
const fileId = crypto.randomUUID()
await writeFile(`./uploads/${fileId}-${file.name}`, file.data)
return {
id: fileId,
filename: file.name,
size: file.size
}
}
}),
// 方式2:PUT 上传到指定位置(替换/覆盖)
// 客户端指定文件 ID,幂等操作
defineRoute({
method: 'PUT',
path: '/files/:fileId',
handler: async ({ req, params }) => {
const file = await parseFile(req)
await writeFile(`./uploads/${params.fileId}`, file.data)
return {
id: params.fileId,
filename: file.name,
replaced: true
}
}
}),
// 方式3:使用原生 formData API
defineRoute({
method: 'POST',
path: '/upload',
handler: async ({ req }) => {
const formData = await req.formData()
const file = formData.get('file') as File
if (!file) {
throw err.badRequest('未上传文件')
}
const bytes = await file.arrayBuffer()
const buffer = Buffer.from(bytes)
await writeFile(`./uploads/${file.name}`, buffer)
return { success: true, filename: file.name }
}
})
])静态文件服务
typescript
import { Server } from 'vafast'
import { staticFiles } from '@vafast/static'
const server = new Server(routes)
server.useGlobalMiddleware(staticFiles({
root: './public',
prefix: '/static'
}))缓存
Redis
typescript
import { defineRoute, defineRoutes } from 'vafast'
import { Redis } from 'ioredis'
const redis = new Redis()
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/users/:id',
handler: async ({ params }) => {
// 尝试从缓存获取
const cached = await redis.get(`user:${params.id}`)
if (cached) {
return JSON.parse(cached)
}
// 从数据库获取
const user = await getUserFromDB(params.id)
// 缓存结果
await redis.setex(`user:${params.id}`, 3600, JSON.stringify(user))
return { user }
}
})
])内存缓存
typescript
import { defineRoute, defineRoutes } from 'vafast'
const cache = new Map()
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/data/:key',
handler: async ({ params }) => {
if (cache.has(params.key)) {
return { data: cache.get(params.key), cached: true }
}
const data = await fetchData(params.key)
cache.set(params.key, data)
return { data, cached: false }
}
})
])任务调度
Cron Jobs
typescript
import { Server } from 'vafast'
import { cron } from '@vafast/cron'
const server = new Server(routes)
server.useGlobalMiddleware(cron({
jobs: [
{
name: 'cleanup',
schedule: '0 2 * * *', // 每天凌晨2点
task: async () => {
console.log('Running cleanup task...')
// 执行清理任务
}
}
]
}))压缩
Gzip/Brotli
typescript
import { Server } from 'vafast'
import { compress } from '@vafast/compress'
const server = new Server(routes)
server.useGlobalMiddleware(compress({
algorithms: ['gzip', 'brotli'],
threshold: 1024
}))模板引擎
HTML 渲染
typescript
import { defineRoute, defineRoutes } from 'vafast'
import { html } from '@vafast/html'
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/',
handler: () => {
return html`
<!DOCTYPE html>
<html>
<head>
<title>Vafast App</title>
</head>
<body>
<h1>Welcome to Vafast!</h1>
</body>
</html>
`
}
})
])测试
单元测试
typescript
import { describe, expect, it } from 'vitest'
import { Server, defineRoute, defineRoutes } from 'vafast'
describe('User Routes', () => {
it('should create a user', async () => {
const routes = defineRoutes([
defineRoute({
method: 'POST',
path: '/users',
handler: ({ body }) => {
return { id: '123', ...body }
}
})
])
const server = new Server(routes)
const request = new Request('http://localhost/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'John', email: 'john@example.com' })
})
const response = await server.fetch(request)
const data = await response.json()
expect(data.id).toBe('123')
expect(data.name).toBe('John')
})
})部署
Docker
dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "run", "start"]环境变量
env
# 数据库
DATABASE_URL="postgresql://user:password@localhost:5432/myapp"
# JWT
JWT_SECRET="your-secret-key"
# Redis
REDIS_URL="redis://localhost:6379"
# 监控
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"SSE 流式响应
AI 聊天流式响应
typescript
import { defineRoute, defineRoutes, Type } from 'vafast'
import OpenAI from 'openai'
const openai = new OpenAI()
const routes = defineRoutes([
defineRoute({
method: 'POST',
path: '/chat/stream',
sse: true, // 显式声明 SSE 端点
schema: {
body: Type.Object({ message: Type.String() })
},
handler: async function* ({ body }) {
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: body.message }],
stream: true,
})
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content
if (content) {
yield { data: { token: content } }
}
}
yield { event: 'done', data: { message: 'Stream completed' } }
},
})
])进度更新
typescript
import { defineRoute, defineRoutes, Type } from 'vafast'
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/tasks/:taskId/progress',
sse: true,
schema: { params: Type.Object({ taskId: Type.String() }) },
handler: async function* ({ params }) {
const { taskId } = params
while (true) {
const task = await getTaskStatus(taskId) // 你的业务逻辑
yield { data: {
status: task.status,
progress: task.progress,
}}
if (task.status === 'completed' || task.status === 'failed') {
return
}
await new Promise(r => setTimeout(r, 2000))
}
},
})
])📖 详细文档见 SSE 流式响应
最佳实践
- 错误处理:始终使用 try-catch 包装异步操作
- 类型安全:使用 TypeBox 进行运行时类型验证
- 中间件顺序:注意中间件的执行顺序
- 性能监控:使用 OpenTelemetry 监控应用性能
- 安全:使用 Helmet 和其他安全中间件
- 测试:为所有路由编写测试用例