fastify / fastify-swagger

Swagger documentation generator for Fastify
MIT License
915 stars 201 forks source link

TypeError: fastify.swagger is not a function #808

Closed akama-aka closed 1 month ago

akama-aka commented 1 month ago

Prerequisites

Fastify version

4.28.0

Plugin version

No response

Node.js version

20.13.1

Operating system

Windows

Operating system version (i.e. 20.04, 11.3, 10)

22631.3880

Description

Hello, I've tried to follow the README.md intruction but sadly there's no sight of life for a normal JavaScript implementation and because of that and the reason that I can't find something related to this error in any Google search I opened this issue. My server.js File looks like that:

const process = require("node:process");
require("dotenv").config();

const fastify = require("fastify")({
  logger: true,
});

fastify.register(require("@fastify/postgres"), {
  connectionString: process.env.DATABASE_URL,
});
fastify.register(require('@fastify/swagger'), {
  exposeRoute:true,
  routePrefix:'/docs',
  specification: {
    path: './example-static-specification.json'
  },
  openapi: {
    openapi:'3.0.0',
    info: {
      title:'Title',
      description:'description',
      version:'1.0.0'
    },
    servers: [
      {url:'https://sub.domain.tld',description: 'desc'},
      {url:'https://sub.sub.domain.tld',description: 'desc'}
    ],
    tags: [
      {name:"name",description:"desc 2"},
      {name:"name2",description:"dd"},
      {name:'name3',description: "ssss"}
    ],
    components: {
      securitySchemes: {
        authorization: {
          type:'apiKey',
          name: 'authorization',
          in:'header'
        },
        "x-auth-agent-token": {
          type:'apiKey',
          name:'x-auth-agent-token',
          in:'header'
        }
      }
    }
  }
})
require(__dirname + "/Controllers/con1").forEach(loadRoute);
require(__dirname + "/Controllers/con2").forEach(loadRoute);
require(__dirname + "/Controllers/con3").forEach(loadRoute);
require(__dirname + "/Controllers/con4").forEach(loadRoute);
require(__dirname + "/Controllers/con5").forEach(loadRoute);

function loadRoute(routeOptions) {
  fastify.route(routeOptions);
}

fastify.listen(
  { host: process.env.SERVER_HOST, port: process.env.SERVER_PORT },
  (err) => {
    if (err) throw err;
  },
)

module.exports = {
  loadRoute,
};

// Set default headers

fastify.addHook('preHandler', (req, rep,done) => {
  rep.headers({
    'Content-Type':'application/json',
    'Access-Control-Allow-Origin':'*',
    'Access-Control-Allow-Methods':'GET,POST,PATCH,DELETE,OPTIONS',
    'Access-Control-Allow-Headers':'Content-Type,Authorization',
    'Access-Control-Allow-Credentials':'true',
    'X-Content-Type-Options':'nosniff',
    'X-Frame-Options':'DENY',
    'X-XSS-Protection':'1;mode=block'
  })
  done();
})

fastify.ready();
fastify.swagger();

As soon as I want to start the server with node server.js I get the in title mentioned error message. And if I change fastify.swagger() to fastify.swaggerI get no error but it also doesnt create anything else

I hope the documentations gets updated for both types of nodejs projects.

Link to code that reproduces the bug

No response

Expected Behavior

No response

climba03003 commented 1 month ago

You are missing await before the fastify.ready

akama-aka commented 1 month ago

You are missing await before the fastify.ready

Then I should get the error that it is not async. Which makes sense because the server.js file is not a module.

climba03003 commented 1 month ago

You are missing await before the fastify.ready

Then I should get the error that it is not async. Which makes sense because the server.js file is not a module.

The document shows you should call fastify.swagger after awaiting the fastify.ready. I am only pointing out you are not following the document.

You can use thenable or callback if top level await is not possible.

akama-aka commented 1 month ago

You are missing await before the fastify.ready

Then I should get the error that it is not async. Which makes sense because the server.js file is not a module.

The document shows you should call fastify.swagger after awaiting the fastify.ready. I am only pointing out you are not following the document.

You can use thenable or callback if top level await is not possible.

You're not pointing out, reading my description. My JavaScript IS NOT A MODULE. So it is not possible to use await randomly in the server file. And I already had it in a faatify.listen function but it also did nothing.

The documentation only shows instructions for a Module JavaScript project, mine is not a module it is a CommonJS project.

climba03003 commented 1 month ago

The documentation only shows instructions for a Module JavaScript project, mine is not a module it is a CommonJS project.

The document show you should await fastify.ready means it should run after the promise is resolved. It doesn't matter it is ESM or CJS, the await is there for a reason. You can change it to thenable or callback, anything that serve the same purpose. But not just remove it (same as not follow the document).

And I already had it in a faatify.listen function but it also did nothing.

That does not ensure fastify.swagger is run after the designed timing. It should place inside the callback if you want to use fastify.listen.

akama-aka commented 1 month ago

The documentation only shows instructions for a Module JavaScript project, mine is not a module it is a CommonJS project.

The document show you should await fastify.ready means it should run after the promise is resolved. It doesn't matter it is ESM or CJS, the await is there for a reason. You can change it to thenable or callback, anything that serve the same purpose. But not just remove it (same as not follow the document).

And I already had it in a faatify.listen function but it also did nothing.

That does not ensure fastify.swagger is run after the designed timing. It should place inside the callback if you want to use fastify.listen.

I've it now like that:

// Set default headers

fastify.listen({ host: process.env.SERVER_HOST, port: process.env.SERVER_PORT }, async (err) => {
    await fastify.ready();
    fastify.swagger();
    if (err) throw err;
  },
)
const process = require("node:process");
const swagger = require('@fastify/swagger');
require("dotenv").config();

const fastify = require("fastify")({
  logger: true,
});

fastify.register(require("@fastify/postgres"), {
  connectionString: process.env.DATABASE_URL,
});
fastify.register(swagger, {
  openapi: {
    openapi:'3.0.0',
    info: {
      title:'my title',
      description:'a desc',
      version:'1.0.0'
    },
    servers: [
      {url:'https://sub.domain.tld',description: 'desc'}
    ],
    tags: [
      {name:"tag1",description:"desc1"},
      {name:"tag2",description:"desc2"},
      {name:'tag3',description: "desc3"}
    ],
    components: {
      securitySchemes: {
        authorization: {
          type:'apiKey',
          name: 'authorization',
          in:'header'
        },
        "x-auth-agent-token": {
          type:'apiKey',
          name:'x-auth-agent-token',
          in:'header'
        }
      }
    }
  }
})

and it still doesnt create yaml or json file anywhere

climba03003 commented 1 month ago

it still doesnt create yaml or json file anywhere

This plugin does not write any file. It returns json or yaml through fastify.swagger

So, you can log and see the result. Then, use the return in the way you want.

akama-aka commented 1 month ago

it still doesnt create yaml or json file anywhere

This plugin does not write any file. It returns json or yaml through fastify.swagger

So, you can log and see the result. Then, use the return in the way you want.

Ahh okay thanks, but it just returns the default data I've set in the fastify.register function. How can I get the routed Endpoints?