How to generate openapi specification with nestjs without running the application

Viewed 4835

We have many APIs written in nodejs, using nestjs framework. We can generate openapi.yaml using SwaggerModule from nestjs. that works perfectly. But the problem is that it needs the API to be up, and therefore that the database is up and running. That's a problem for us in our CI/CD, because we need to generate openapi specification before running the API.

Is it possible to generate openapi specification from our code, without needing to run the application? Or maybe is there a simple way to mock our database?

Thanks for your help

2 Answers

The short answer is no, there isn't a way to generate the docs without running the NestJS application. However, you can generate a JSON file representing the OpenAPI documentation and then generate a static website from there. This issue gets you half-way there:

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const options = new DocumentBuilder()
    .setTitle('Cats example')
    .setDescription('The cats API description')
    .setVersion('1.0')
    .addTag('cats')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  const outputPath = path.resolve(process.cwd(), 'swagger.json');
  writeFileSync(outputPath, JSON.stringify(document), { encoding: 'utf8'});

  await app.close();
}
bootstrap();

This will generate a file swagger.json containing the OpenAPI specification. From there, you can use a tool like Spectacle to generate the actual HTML:

npx spectacle-docs -t public/docs swagger.json

An even less documented feature is the ability to retrieve a JSON representation of the OpenAPI specification from the regular endpoint using only curl.

Let's say you have a standard @nestjs/swagger integration that publishes the OpenAPI docs to /docs/:

  const options = new DocumentBuilder()
    .setTitle('core-api')
    .setDescription('The core API description')
    .setVersion('3.0')
    .addTag('core-api')
    .setBasePath(version)
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('docs', app, document);

If you browser to http:/localhost:3000/docs/, you can access the HTML version of the docs. However, if you browser to http://localhost:3000/docs-json you will receive a JSON representation. Simply append -json to whatever you spec path is.

Tying this all together, you can integrate this into a CI pipeline with a little hackery. I have integrated this into a Gitlab CI pipeline like so:

script:
  - until nc -vz $API_IP 3000; do sleep 1; done
  - curl http://$API_IP:3000/docs-json -o swagger.json
  - npx spectacle-docs -t public/docs swagger.json

In your CI pipeline, you'll still have to run your NestJS application and as well as Mongo and any other dependant services required for it to start, but once you generate the JSON you can stop your application, build the static HTML site and publish it elsewhere.

Related