Nx NestJs - How to autogenerate OpenApi/Swagger specs
Iulian Preda
Posted on May 8, 2022
Hello everyone, short article this time.
As I started using NestJs with Nx I noticed a point of contingency, there are still debates on how to activate OpenApi/Swagger in NestJs with the auto documentation option.
Fear no more, at the end of this tutorial that problem will be solved.
Versions used
I am using the latest Nx at the time of writing, which is V14, with NestJs 8.0 and NestJs Swagger 5.2.
Packages
Install the required package first, if you use express install npm install --save @nestjs/swagger swagger-ui-express
otherwise, for fastify use npm install --save @nestjs/swagger fastify-swagger
Add Swagger Module
In main.ts
from your NestJs' project folder add the following:
function setupOpenApi(app: INestApplication) {
const config = new DocumentBuilder().setTitle('API Documentation').setVersion('1.0').addTag('api').build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
}
then in the bootstrap
function just call the setupOpenApi
function.
My entire main.ts
looks like this, take note that I prefered the following options:
- I used Fastify, because I don't have any hard dependency on an express middleware and it improves the performance
- I Used a global prefix, thus the I had to set
useGlobalPrefix:true
in the function above - The global prefix I used is the default
api
that conflicts with the default route for OpenApi which in the documentation is coincidentlyapi
. If you keep them like this without adding theuseGlobalPrefix: true
flag then you will be able to access both the APIs and the OpenAPI onhttp://localhost:3000/api
but you will notice that the documentation is wrong as it doesn't contain theglobalPrefix
used. To fix this we will have to set theuseGlobalPrefix: true
flag for OpenAPI and access the documentation athttp://localhost:3000/api/api
which looks weird so I customized it tohttp://localhost:3000/api/openApi
Working example bellow:
/**
* This is not a production server yet!
* This is only a minimal backend to get started.
*/
import { INestApplication, Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app/app.module';
async function bootstrap() {
const fastifyOptions: ConstructorParameters<typeof FastifyAdapter>[0] = {
logger: true,
};
const fastifyAdapter = new FastifyAdapter(fastifyOptions);
const app = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyAdapter);
const globalPrefix = 'api';
app.setGlobalPrefix(globalPrefix);
setupOpenApi(app);
const port = process.env.PORT || 3333;
await app.listen(port);
Logger.log(`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`);
}
bootstrap();
function setupOpenApi(app: INestApplication) {
const config = new DocumentBuilder().setTitle('API Documentation').setVersion('1.0').addTag('api').build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('openApi', app, document, { useGlobalPrefix: true });
}
Right now you are ready to use the manual documentation part of the package, but we both know you are not here for that
Auto Documentation
This will be rather short, we will have 2, non-hacky, ways to do this.
Nest-Cli.json - Not suggested
Just create a nest-cli.json
file at the root of the project, then add
{
"collection": "@nestjs/schematics",
"sourceRoot": "apps",
"compilerOptions": {
"plugins": [
{
"name": "@nestjs/swagger/plugin",
"options": {
"dtoFileNameSuffix": [".entity.ts", ".dto.ts"],
"controllerFileNameSuffix": [".controller.ts"],
"classValidatorShim": true,
"dtoKeyOfComment": "description",
"controllerKeyOfComment": "description",
"introspectComments": true
}
}
]
}
}
Do not be scared of the above settings, they are just the defaults to be more explicit. What is really changed is the sourceRoot
which in the case on NX (at least for the presets with apps) is the folder apps
.
This should detect your parameters, and class names, but will most likely not see what is inside your classes and they will appear empty.
TsPlugin - Recommended, more customizable
Go to your project.json
in your NestJs' project folder or angular.json
in the root folder for older version and search for the project you need. We will need to alter the build
command.
The entire build command is displayed bellow
"build": {
"executor": "@nrwl/node:webpack",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/apps/api",
"main": "apps/api/src/main.ts",
"tsConfig": "apps/api/tsconfig.app.json",
"tsPlugins": [
{
"name": "@nestjs/swagger/plugin",
"options": {
"dtoFileNameSuffix": [".entity.ts", ".dto.ts"],
"controllerFileNameSuffix": [".controller.ts"],
"classValidatorShim": true,
"dtoKeyOfComment": "description",
"controllerKeyOfComment": "description",
"introspectComments": true
}
}
],
"assets": ["apps/api/src/assets"]
},
As you can notice we added a custom Webpack TsPlugin as specified in the documentation above this https://docs.nestjs.com/openapi/cli-plugin#integration-with-ts-jest-e2e-tests.
As mentioned, this is the recommended approach, it will see all the classes from anywhere in the monorepo as long as they are imported into the project.
Final details
Keep in mind the following:
- You can use only
class
es notinterface
es - You need to append a
.dto.ts
or.entity.ts
unless you change that
Thanks for reading!
Posted on May 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.