typescriptswaggeropenapifastifyfastify-swagger

How to setup @fastify/swagger and @fastify/swagger-ui with TypeScript?


I new to Fastify and I am trying to setup swagger documentation with it. I am using TypeScript and all the examples that I found were using JavaScript and require syntax.

I tried to follow the examples where was possible and now my documentation is not showing anything for the / route I created.

Here is my current code:

import fastifySwagger from '@fastify/swagger';
import fastifySwaggerUi from '@fastify/swagger-ui';
import Fastify from 'fastify';

import { errorBoundary } from './plugins/errorBoundary';

const fastify = Fastify({
  logger: true
});

const port = process.env.PORT || 3003;

// Set custom error handler.
fastify.setErrorHandler(errorBoundary);

// Register @fastify/swagger plugin.
fastify.register(fastifySwagger, {
  openapi: {
    info: {
      title: 'Forest Fire API',
      description: 'Forest Fire API Documentation',
      version: '1.0.0'
    },
    servers: [
      {
        url: 'http://localhost'
      }
    ],
    components: {
      securitySchemes: {
        bearerAuth: {
          type: 'http',
          scheme: 'bearer'
        }
      }
    },
    tags: [
      {
        name: 'Root',
        description: 'Root endpoints'
      }
    ]
  }
});

// Register @fastify/swagger-ui plugin.
fastify.register(fastifySwaggerUi, {
  routePrefix: '/docs',
  uiConfig: {
    docExpansion: 'full',
    deepLinking: false
  },
  uiHooks: {
    onRequest: function (_request, _reply, next) {
      next();
    },
    preHandler: function (_request, _reply, next) {
      next();
    }
  },
  staticCSP: true,
  transformStaticCSP: (header) => header,
  transformSpecification: (swaggerObject) => {
    return swaggerObject;
  },
  transformSpecificationClone: true
});

// Root route.
fastify.get(
  '/',
  {
    schema: {
      description: 'Root endpoint',
      tags: ['Root'],
      response: {
        200: {
          description: 'Succesful response',
          type: 'object',
          properties: {
            message: { type: 'string' },
            result: { type: 'object', nullable: true }
          }
        }
      }
    }
  },
  async function (request, reply) {
    return reply.send({
      message: 'Hello World',
      result: null
    });
  }
);

async function start() {
  await fastify.listen({
    port: port as number
  });

  fastify.swagger();
}

start().catch((err) => {
  fastify.log.error(err);
  process.exit(1);
});

When I access the /docs route, the following is presented:

Swagger UI without / route docs

I was expecting the / route to be documented in the page. What are the possible errors?


Solution

  • Explanation

    You need to register route as a plugin in order to make routes appear in swagger.

    app.register((app, options, done) => {
            app.get("/", {
                schema: {
                    tags: ["Default"],
                    response: {
                        200: {
                            type: "object",
                            properties: {
                                anything: { type: "string" },
                            },
                        },
                    },
                },
                handler: (req, res) => {
                    res.send({ anything: "meaningfull" });
                },
            });
            done();
        });
    

    Complete Code:

    import dotenv from "dotenv";
    import { fastify } from "fastify";
    import fastifySwagger from "@fastify/swagger";
    import fastifySwaggerUi from "@fastify/swagger-ui";
    dotenv.config();
    const app = fastify({ logger: true });
    
    const swaggerOptions = {
        swagger: {
            info: {
                title: "My Title",
                description: "My Description.",
                version: "1.0.0",
            },
            host: "localhost",
            schemes: ["http", "https"],
            consumes: ["application/json"],
            produces: ["application/json"],
            tags: [{ name: "Default", description: "Default" }],
        },
    };
    
    const swaggerUiOptions = {
        routePrefix: "/docs",
        exposeRoute: true,
    };
    
    app.register(fastifySwagger, swaggerOptions);
    app.register(fastifySwaggerUi, swaggerUiOptions);
    
    app.register((app, options, done) => {
        app.get("/", {
            schema: {
                tags: ["Default"],
                response: {
                    200: {
                        type: "object",
                        properties: {
                            anything: { type: "string" },
                        },
                    },
                },
            },
            handler: (req, res) => {
                res.send({ anything: "meaningfull" });
            },
        });
        done();
    });
    
    app.listen(
        {
            port: Number(process.env.APP_PORT) ?? 3000, // Pulled from env file.
            host: process.env.APP_HOST ?? "localhost",
        },
        (err, address) => {
            if (err) {
                console.error(err);
                process.exit(1);
            }
        }
    );