log
码中赤兔

Fastify 最佳实践 #5: Swagger 文档生成

发布于 2025年6月24日
更新于 2025年6月26日
13 分钟阅读
TypeScript

在开发服务端API时,维护一份准确、实时、易于理解的API文档是提升团队协作效率和外部开发者体验的关键。手写文档不仅耗时,还极易出现代码与文档不一致的情况。幸运的是,在Fastify生态中,我们可以通过 @fastify/swagger@fastify/swagger-ui 这两个利器,将我们的代码(特别是Zod Schema)直接转化为专业、可交互的Swagger文档,实现“代码即文档”。

首先,我们需要安装相关依赖:

npm install @fastify/swagger @fastify/swagger-ui

配置 Swagger 插件

接下来,我们需要在 Fastify 实例上注册这两个插件。在一个独立的插件文件(例如 plugins/swagger.ts)中进行配置是很好的实践。

这里的核心是让 @fastify/swagger 能够理解我们在上一篇文章中大力推崇的 Zod Schema。

import swagger from '@fastify/swagger';
import swaggerUi from '@fastify/swagger-ui';
import fastify, { FastifyInstance } from 'fastify';
import { jsonSchemaTransform } from 'fastify-type-provider-zod';

export const setupSwagger = async (server: FastifyInstance) => {
  // 注册 swagger 核心插件
  await server.register(swagger, {
    // 关键:让 swagger 支持 Zod schema
    transform: jsonSchemaTransform,
    openapi: {
      openapi: '3.0.0', // OpenAPI 版本
      info: {
        // 文档基本信息
        title: 'Fastify 最佳实践项目 API',
        description: '这是一个示例项目的API文档',
        version: '0.1.0',
      },
      servers: [
        // API 服务器列表
        {
          url: `http://127.0.0.1:8080`,
          description: '开发服务器',
        },
      ],
      tags: [
        // API 分类标签
        { name: 'user', description: '用户相关API' },
        { name: 'health', description: '健康检查API' },
      ],
      // 可选:添加全局安全认证配置
      components: {
        securitySchemes: {
          bearerAuth: {
            type: 'http',
            scheme: 'bearer',
            bearerFormat: 'JWT',
          },
        },
      },
      security: [
        {
          bearerAuth: [],
        },
      ],
    },
  });

  // 注册 swagger UI 插件,用于提供可视化文档界面
  await server.register(swaggerUi, {
    routePrefix: '/doc', // swagger 文档访问路径
    uiConfig: {
      docExpansion: 'full',
      deepLinking: false,
    },
    uiHooks: {
      onRequest: function (_request: any, _reply: any, next: any) {
        next();
      },
      preHandler: function (_request: any, _reply: any, next: any) {
        next();
      },
    },
    staticCSP: false,
    transformSpecificationClone: true,
    logLevel: 'silent',
  });
};

jsonSchemaTransform 的作用

你可能已经注意到,这里的关键是 transform: jsonSchemaTransform 配置。这个从 fastify-type-provider-zod 导入的函数,其作用就是一座桥梁,它能自动将你在路由中定义的 Zod Schema 转换成 Swagger(OpenAPI 规范)所要求的 JSON Schema 格式。没有它,Swagger 将无法理解我们的 Zod 类型定义。

在路由中添加文档信息

完成插件配置后,我们还需要在每个API路由的 schema 选项中提供一些元数据,Swagger 会读取这些信息来生成文档。

让我们来看一个具体的例子:

import { FastifyInstance } from 'fastify';
import type { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod';

const routes = async (fastify: FastifyInstance) => {
  fastify.withTypeProvider<ZodTypeProvider>().get(
    '/user/:id', // API URL
    {
      schema: {
        summary: '获取单个用户信息',
        description: '根据用户ID查询详细信息。',
        tags: ['user'], // API 分类
        params: z.object({
          id: z.string().uuid().describe('用户唯一ID (UUID格式)'), // Zod的 `.describe()` 方法会被自动转换成字段描述
        }),
        response: {
          200: z
            .object({
              id: z.string().uuid(),
              name: z.string(),
              email: z.string().email(),
            })
            .describe('成功响应'),
          404: z
            .object({
              message: z.string(),
            })
            .describe('用户未找到时的响应'),
        },
        // 表示此接口需要 bearerAuth 认证
        security: [{ bearerAuth: [] }],
      },
    },
    async (req, reply) => {
      // ... 业务逻辑 ...
      const user = { id: req.params.id, name: 'Millet', email: 'millet@example.com' };
      return reply.status(200).send(user);
    },
  );
};

export default routes;

总结

通过上述配置,我们不仅为项目生成了专业、可交互的 API 文档,更重要的是,这份文档是与我们的代码完全同步的 “活文档”。每当你的 Zod Schema 发生变化,文档就会自动更新,彻底告别了因手写文档而导致代码与文档不一致的烦恼。这大大提升了开发效率和 API 的可维护性,是现代服务端开发中不可或缺的一环。


在我的开源项目中,我将关于 Swagger 的配置封装在了一个独立的插件 (04.swagger.plugin.ts) 中,并通过 fastify-autoload 自动加载,欢迎参考:

fastify-best-practice on GitHub

关于

分享技术见解、经验和思考的个人博客

联系方式

  • Email: hushukang_blog@proton.me
  • GitHub

© 2025 码中赤兔. 版权所有