mcpField
F
fastify-v5

fastify-v5

github.com/blockmatic开发1221 次安装5 周前更新
代码仓库

关于 fastify-v5

面向使用 Fastify v5 和 TypeScript 的开发者,提供基于 TypeBox 的类型安全路由、插件、钩子与测试实践。指南涵盖从模式定义生成 OpenAPI,以及用 inject() 测试路由。

主要功能

  1. 01用 TypeBox 定义请求与响应模式
  2. 02从模式推断路由类型
  3. 03从模式生成 OpenAPI
  4. 04开发插件并使用请求钩子
  5. 05通过 inject() 测试路由

适用场景

  1. 01构建类型安全的 Fastify API
  2. 02为路由生成 OpenAPI 规范
  3. 03编写可复用插件与请求生命周期逻辑
  4. 04对路由进行黑盒测试

安装

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

$npx skills add https://github.com/blockmatic/basilic-skills --skill fastify-v5

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
hooks.md
instance-config.md
openapi-integration.md
plugins.md
testing.md
templates/
hook-plugin.ts
plugin.ts
route-schema.ts
test-utils.ts

详细介绍

技能:fastify

适用范围

  • 适用于:Fastify v5+、TypeBox schemas、类型安全的路由定义、自动生成 OpenAPI、插件、钩子、测试
  • 不适用于:数据库集成(请参阅 drizzle-orm)

前提条件

  • Fastify v5+
  • 使用 @fastify/type-provider-typebox 作为 TypeBox 类型提供程序
  • 使用 @sinclair/typebox 定义 schema
  • TypeScript v5+,并启用严格模式

原则

  • 使用 TypeBox schemas 验证路由(params、query、body、response)
  • 使用 TypeBoxTypeProvider 自动从 schemas 推断类型
  • 为所有状态码定义 response schemas
  • 使用 schemas 生成 OpenAPI(通过 @fastify/swagger)
  • 请求类型(request.params、request.query、request.body)从 schemas 推断
  • 根据 schema 自动进行响应验证

约束

必须
  • 使用 TypeBoxTypeProvider 确保类型安全:fastify.withTypeProvider<TypeBoxTypeProvider>()
  • 为所有状态码定义 response schemas
  • 使用 TypeBox Type.* 构造函数定义 schema
应当
  • 在路由 schemas 中使用 operationId 生成 OpenAPI
  • 使用 tags 在 OpenAPI 文档中组织路由
  • 为错误情况定义错误响应 schemas
避免
  • 手动进行类型断言(类型会从 schemas 推断)
  • 跳过 response schema 定义
  • 在同一路由中混用 TypeBox 和其他 schema 库

交互

模式

路由 Schema 模式
import { Type } from '@sinclair/typebox'
import type { FastifyPluginAsync } from 'fastify'

const UserSchema = Type.Object({
  id: Type.String(),
  email: Type.String({ format: 'email' }),
  name: Type.String(),
})

const userRoutes: FastifyPluginAsync = async fastify => {
  fastify.get('/users/:id', {
    schema: {
      operationId: 'getUser',
      params: Type.Object({ id: Type.String() }),
      response: {
        200: UserSchema,
        404: Type.Object({ code: Type.String(), message: Type.String() }),
      },
    },
  }, async (request, reply) => {
    // request.params.id is typed
    const { id } = request.params
    return reply.send(user)
  })
}
Schema 类型
Type.String()
Type.Number()
Type.Boolean()
Type.Object({ id: Type.String() })
Type.Array(Type.String())
Type.Optional(Type.String())
Type.Union([Type.String(), Type.Number()])

完整示例请参阅路由 Schema 模板。

实例配置

使用 TypeBox 类型提供程序、logger 和请求设置配置 Fastify 实例:

import type { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import Fastify, { LogController } from 'fastify'

const fastify = Fastify({
  logger: {
    level: 'info',
    transport: process.env.NODE_ENV === 'development' ? {
      target: 'pino-pretty',
    } : undefined,
  },
  trustProxy: true,
  bodyLimit: 1048576, // 1MB
  requestTimeout: 30000,
  requestIdHeader: 'x-request-id',
  logController: new LogController({ requestIdLogLabel: 'reqId', disableRequestLogging: false }),
}).withTypeProvider<TypeBoxTypeProvider>()

完整配置请参阅实例配置。

插件开发

使用 fastify-plugin 创建可复用插件,实现非封装行为:

import type { FastifyPluginAsync } from 'fastify'
import fp from 'fastify-plugin'

const myPlugin: FastifyPluginAsync = async fastify => {
  // Plugin logic
}

export default fp(myPlugin, {
  name: 'my-plugin',
})

示例请参阅插件模式和插件模板。

钩子(请求生命周期)

使用钩子拦截请求、修改响应或处理错误:

fastify.addHook('onRequest', async (request, reply) => {
  // Add security headers, logging, etc.
})

fastify.addHook('onResponse', async (request, reply) => {
  // Modify response, add headers, etc.
})

fastify.addHook('onError', async (request, reply, error) => {
  // Handle errors
})

模式请参阅钩子指南和钩子插件模板。

使用 inject() 进行测试

使用 Fastify 的 inject() 方法测试路由,进行黑盒测试:

const response = await fastify.inject({
  method: 'GET',
  url: '/users/123',
})

expect(response.statusCode).toBe(200)
const data = JSON.parse(response.body)

有关设置,请参阅测试模式和测试工具模板。

流式响应

处理流式响应(例如,Server-Sent Events、文本流):

fastify.post('/stream', {
  schema: {
    response: {
      200: Type.String({ description: 'Streaming response' }),
    },
  },
}, async (request, reply) => {
  reply.header('Content-Type', 'text/event-stream')
  reply.header('Cache-Control', 'no-cache')
  return reply.send(stream)
})
常用插件
速率限制
import rateLimit from '@fastify/rate-limit'

await fastify.register(rateLimit, {
  max: 100,
  timeWindow: 60000,
  keyGenerator: request => request.ip,
})
CORS
import cors from '@fastify/cors'

await fastify.register(cors, {
  origin: (origin, callback) => {
    // Validate origin
    callback(null, true)
  },
  credentials: false,
})
错误处理器
fastify.setErrorHandler((error, request, reply) => {
  // Global error handling
  reply.status(error.statusCode ?? 500).send({
    code: 'ERROR',
    message: error.message,
  })
})
优雅关闭

处理进程信号以实现优雅关闭:

const shutdown = async (signal: string) => {
  fastify.log.info({ signal }, 'Shutting down')
  await fastify.close()
  process.exit(0)
}

process.on('SIGTERM', () => shutdown('SIGTERM'))
process.on('SIGINT', () => shutdown('SIGINT'))
AutoLoad 模式

使用 @fastify/autoload 自动发现插件和路由:

import AutoLoad from '@fastify/autoload'

await fastify.register(AutoLoad, {
  dir: path.join(__dirname, 'plugins'),
  forceESM: true,
})

参考资料

评论

支持 Markdown