fastify / help

Need help with Fastify? File an Issue here.
https://www.fastify.io/
65 stars 8 forks source link

Migration from @fastify/swagger 7 to 8 #957

Open dargolith opened 11 months ago

dargolith commented 11 months ago

πŸ’¬ Question here

How do I migrate my current fastify-swagger from 7.x to 8.x (I have read the migration guide, but it is still not working)?

Directory structure:

...
src
|   index.js
swagger
β”‚   index.yaml
β”‚
β”œβ”€β”€β”€definitions
β”‚   β”œβ”€β”€β”€entities
β”‚   β”‚       Asset.yaml
β”‚   β”‚       ...
β”‚   β”‚
β”‚   └───responses
β”‚           500.yaml
β”‚
└───paths
    β”œβ”€β”€β”€asset
    β”‚       create.yaml
    β”‚       delete.yaml
    β”‚       read.yaml
    β”‚       update.yaml
    β”œβ”€β”€β”€ ...
    ...
...

index.js (before, working fine with @fastify/swagger 7.4.1)

import { fastify } from 'fastify';
import fastifySwagger from '@fastify/swagger';
import fastifyCors from '@fastify/cors';
...

const start = async () => {
...
  console.info('Loading API...');
  const app = fastify({});
  app.get('/', (_, response) => response.redirect('/docs')); // default to swagger docs
  app.register(createApi(storage));
  app.register(fastifyCors, { origin: '*' });
  app.register(fastifySwagger, {
    mode: 'static',
    specification: { path: './swagger/index.yaml' },
    routePrefix: '/docs',
    exposeRoute: true,
  });
  console.info('API Loaded.');

  app.listen({ host: '0.0.0.0', port: SERVICE_PORT }, (error, address) => {
    if (error) {
      console.error(error);
      process.exit(1);
    }
    console.info(`Server started. Listening on ${address}`);
  });
};

index.js (now, not working)

import { fastify } from 'fastify';
import fastifySwagger from '@fastify/swagger';
import fastifySwaggerUi from '@fastify/swagger-ui';
import fastifyCors from '@fastify/cors';
...

const start = async () => {
...
  console.info('Loading API...');
  const app = fastify({});
  app.get('/', (_, response) => response.redirect('/docs')); // default to swagger docs
  app.register(createApi(storage));
  app.register(fastifyCors, { origin: '*' });
  app.register(fastifySwagger, {
    mode: 'static',
    specification: { path: './swagger/index.yaml' },
  });
  app.register(fastifySwaggerUi, {
    routePrefix: '/docs',
  });

  console.info('API Loaded.');

  app.listen({ host: '0.0.0.0', port: SERVICE_PORT }, (error, address) => {
    if (error) {
      console.error(error);
      process.exit(1);
    }
    console.info(`Server started. Listening on ${address}`);
  });
};
...

swagger/index.yaml

swagger: "2.0"
info:
  title: "My Service"
  description: >
    Service providing an API.
  version: "1.0.0"
schemes:
  - https
  - http
paths:
  # Asset
  /asset/create:
    $ref: ./paths/asset/create.yaml
  /asset/read:
    $ref: ./paths/asset/read.yaml
  /asset/update:
    $ref: ./paths/asset/update.yaml
  /asset/delete:
    $ref: ./paths/asset/delete.yaml

...

Errors in the UI:

Errors

Resolver error at paths./asset/create.$ref
Could not resolve reference: undefined Route GET:/docs/paths/asset/create.yaml not found
Resolver error at paths./asset/read.$ref
Could not resolve reference: undefined Route GET:/docs/paths/asset/read.yaml not found
Resolver error at paths./asset/update.$ref
Could not resolve reference: undefined Route GET:/docs/paths/asset/update.yaml not found
Resolver error at paths./asset/delete.$ref
Could not resolve reference: undefined Route GET:/docs/paths/asset/delete.yaml not found

I've tried with all the options in the migration instructions as well, but no difference.

It does work if I use the baseDir option, but I don't want to specify an absolute path, and the docs says that it should use the directory where the main spec is located, which I assume would be my "swagger" directory, since my index.yaml main spec file is located there.

What am I doing wrong?

Your Environment

dargolith commented 9 months ago

After waiting for a few months for an answer I decided to try again and do some more research. After meddling with it and testing some things I finally found something that made it work.

For anyone else having this problem when serving a static specification... In order to get it to work I used @fastify/static to serve the folder with the swagger specification. Not sure if this is the way to go, but it worked at least.


import { fastify } from 'fastify';
import { fastifyStatic } from '@fastify/static';
import { fastifySwagger } from '@fastify/swagger';
import { fastifySwaggerUi } from '@fastify/swagger-ui';
import { fastifyCors } from '@fastify/cors';
import path from 'path';
...

const start = async () => {
...
  console.info('Loading API...');
  const app = fastify({});
  app.get('/', (_, response) => response.redirect('/docs')); // default to swagger docs
  app.register(createApi(storage));
  app.register(fastifyCors, { origin: '*' });
  app.register(fastifyStatic, {
    root: path.join(__dirname, '..', 'swagger'),
    prefix: '/docs/',
  });
  app.register(fastifySwagger, {
    mode: 'static',
    specification: { path: './swagger/index.yaml' },
  });
  app.register(fastifySwaggerUi, {
    routePrefix: '/docs',
  });

  console.info('API Loaded.');

  app.listen({ host: '0.0.0.0', port: SERVICE_PORT }, (error, address) => {
    if (error) {
      console.error(error);
      process.exit(1);
    }
    console.info(`Server started. Listening on ${address}`);
  });
};
...
Uzlopak commented 9 months ago

Actually @fastify/swagger-ui uses @fastify/static. So why are you using static?

dargolith commented 9 months ago

Actually @fastify/swagger-ui uses @fastify/static. So why are you using static?

That was the only way I got it working, please enlighten me how to do it otherwise. If I remove the static plugin swagger-ui won't find the paths to my swagger specification files. It will find the swagger/index.yaml, but no other files of the spec.

climba03003 commented 9 months ago

Have you tried the baseDir option in @fastify/swagger-ui?

dargolith commented 8 months ago

Have you tried the baseDir option in @fastify/swagger-ui?

Yeah, I tried that. Didn't get it working. Let me try some more with it.

dargolith commented 8 months ago

I've tried with baseDir now and I can't get it to work. This is what I'm at right now without the static plugin. Uncommenting / commenting the specification.baseDir for @fastify/swagger does no difference.

NOTE: I've renamed my "swagger" folder to "openapi". I switched to a newer spec.

Uncommenting the static-plugin section makes it work.

  // app.register(fastifyStatic, {
  //   root: path.join(__dirname, '..', 'openapi'),
  //   prefix: '/docs/',
  // });
  await app.register(fastifySwagger, {
    mode: 'static',
    specification: {
      path: './openapi/index.yaml',
      // baseDir: path.join(__dirname, '..', 'openapi'),
    },
    routePrefix: '/docs',
    exposeRoute: true,
  });
  await app.register(fastifySwaggerUi, {
    mode: 'static',
    // baseDir: path.join(__dirname, '..', 'openapi'),
    routePrefix: '/docs',
    exposeRoute: true,
  });

Regardless of using the specification.baseDir in @fastify/swagger I get the same error in swagger-ui. The main spec can be opened, but the refs do not resolve:

Resolver error at paths./asset/create.$ref
Could not resolve reference: undefined Route GET:/docs/paths/asset/create.yaml not found

I really don't think I should have to use the baseDir since my main spec file is located in the root of the folder with my other spec files. And as expected the baseDir option does no difference.

When using baseDir in @fastify/swagger-ui the swagger UI page doesn't load at all.

I've also tried without custom /docs prefixes, using the default /documentation instead. Same deal.

It seems really strange to me that it doesn't work with just the code above. The example here: https://github.com/fastify/fastify-swagger/blob/master/examples/static-yaml-file.js

should really include how to setup a static specification with referenced files, because I doubt it would work using $refs. Though to me no more configuration should be needed if the references are in the same folder. Is this a bug?

Uzlopak commented 8 months ago

Its really strange. Can you provide a repository to clone and test?

dargolith commented 8 months ago

Its really strange. Can you provide a repository to clone and test?

Sure! Try this: https://github.com/dargolith/fastify-swagger-static-example

(If you uncomment the static section it works)

climba03003 commented 8 months ago

We should really split baseDir to websiteDir and specificationDir. It is currently mixed togather which causing problem.

https://github.com/fastify/fastify-swagger-ui/blob/master/lib/routes.js#L203-L227

dargolith commented 8 months ago

We should really split baseDir to websiteDir and specificationDir. It is currently mixed togather which causing problem.

https://github.com/fastify/fastify-swagger-ui/blob/master/lib/routes.js#L203-L227

Yes, that sounds like a good plan. However, it should work without setting baseDir as well if it is correctly located relative to the main spec file, right? So in this case if I point the plugin to my main spec the $refs should be reachable as long as they are in the same folder structure, or?

If not for some reason, then the docs must be really clear that the static default configuration does not work for split specs (using $refs) and also give an example on how to configure it.