Sathish
Sathish

Reputation: 309

NestJs + Swagger documentation based on versioning

I have built a nestjs webapi and implemented versioning at controller and action level as per https://docs.nestjs.com/techniques/versioning

The solution i am looking into is, i want to generate 2 different swagger based on the controller version. For example, i have 2 controller defined for 2 different version. if i hit [example.com/v1/swagger] , it should load only v1 version controller swagger doc and similarly for v2

Upvotes: 9

Views: 7056

Answers (3)

William McLaughlin
William McLaughlin

Reputation: 11

I was recently looking into how to separate out the API versions into separate swagger documents and wanted to post my solution to the issue on GitHub, but it's been locked so I'll leave the solution here.

If you look at the SwaggerModule.setup() method documentation, it accepts a SwaggerCustomOptions object as the 4th parameter. Inside the options object, there is a property for patchDocumentOnRequest that allows you to define a custom function that will be executed on every request for the documentation and allows you to manipulate the document before it is served.

Using this function, we can filter out the paths that do not match the requested version.

  SwaggerModule.setup(':version/swagger', app, swaggerDocument, {
    patchDocumentOnRequest: (req, _res, document) => {
      // NOTE: Make a deep copy of the original document or it will be modified on subsequent calls!
      const copyDocument = JSON.parse(JSON.stringify(document));
      const version = (req as Request).params.version;
      const isValidVersion = /^v[0-9]+$/;

      if (!version || !isValidVersion.test(version)) {
        return;
      }

      for (const route in document.paths) {
        if (route.startsWith(`/${version}`)) {
          continue;
        }
        delete copyDocument.paths[route];
      }

      return copyDocument;
    },
  });

Note: This solution will only work for URI versioned APIs.

Upvotes: 1

marnutux
marnutux

Reputation: 135

app.enableVersioning(); should be called before SwaggerModule.createDocument(...)

Source: https://github.com/nestjs/swagger/issues/1495#issuecomment-898311614

Upvotes: 6

Michael P. Scott
Michael P. Scott

Reputation: 714

I recently updated my API to support versioning. I couldn't get the Swagger docs to load correctly. Here is my solution, I hope it helps!

Before, we had used app.setGlobalPrefix(APP_ROUTE_PREFIX) to define the prefix.

const APP_ROUTE_PREFIX = 'api/v2';
app.setGlobalPrefix(APP_ROUTE_PREFIX);

Swagger docs were mounted as:

SwaggerModule.setup(`${APP_ROUTE_PREFIX}/docs`, app, document);

To adopt versioning, the following was changed.

  1. Route prefix no longer includes the version; let Nestjs handle it.
const APP_ROUTE_PREFIX = 'api';
  1. Versioning is enabled, with a default of '2', mimicking previous behavior.
  app
    .enableVersioning({ type: VersioningType.URI, defaultVersion: '2' })
    .setGlobalPrefix(APP_ROUTE_PREFIX);
  1. To get Swagger docs to mount correctly, we had to use a variable :version in the path.
  SwaggerModule.setup(`${APP_ROUTE_PREFIX}/:version/docs`, app, document);
  1. Next, we changed on a per-controller basis the controllers that need to adopt versioning.
@Controller({ path: 'objects/:id', version: ['2', '3'] })
  1. Finally, we changed on a per-route basis the handlers that support multiple versions.
  @Version('2')
  getPageV2(): Promise<Observable<unknown>> {
    return this.service.getOkayData();
  }

  @Version('3')
  getPageV3(): Promise<Observable<unknown>> {
    return this.service.getBetterData();
  }

Upvotes: 5

Related Questions