OpenAPI (Swagger)

Warning The techniques in this section require TypeScript, and are not available if your app is written using vanilla JavaScript.

The OpenAPI specification is a language-agnostic definition format used to describe RESTful APIs. Nest provides a dedicated module which allows generating such a specification by leveraging decorators.

Installation#

To begin using it, we first install the required dependencies.


$ npm install --save @nestjs/swagger swagger-ui-express

If you use fastify, install fastify-swagger instead of swagger-ui-express:


$ npm install --save @nestjs/swagger fastify-swagger

Bootstrap#

Once the installation process is complete, open the main.ts file and initialize Swagger using the SwaggerModule class:


import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ApplicationModule } from './app.module';

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

  const options = new DocumentBuilder()
    .setTitle('Cats example')
    .setDescription('The cats API description')
    .setVersion('1.0')
    .addTag('cats')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('api', app, document);

  await app.listen(3000);
}
bootstrap();

The DocumentBuilder helps to structure a base document that conforms to the OpenAPI Specification. It provides several methods that allow setting such properties as title, description, version, etc. In order to create a full document (with all HTTP routes defined) we use the createDocument() method of the SwaggerModule class. This method takes two arguments, an application instance and a Swagger options object.

Once we create a document, we can call setup() method. It accepts:

  1. the path to mount the Swagger UI
  2. an application instance
  3. the document object instantiated above

Now you can run the following command to start the HTTP server:


$ npm run start

While the application is running, open your browser and navigate to http://localhost:3000/api. You should see the Swagger UI.

The SwaggerModule automatically reflects all of your endpoints. Also, in order to display the Swagger UI, @nestjs/swagger makes use of either swagger-ui-express or fastify-swagger depending on the platform.

Hint To generate and download a Swagger JSON file, navigate to http://localhost:3000/api-json in your browser (assuming that your Swagger documentation is available under http://localhost:3000/api).

Route parameters#

The SwaggerModule searches for all @Body(), @Query(), and @Param() decorators in route handlers to generate the API document. It also creates corresponding model definitions by taking advantage of reflection. Consider the following code:


@Post()
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}
Hint To explicitly set the body definition use the @ApiBody() decorator (@nestjs/swagger package).

Based on the CreateCatDto, the module definition will be created:

As you can see, the definition is empty although the class has a few declared properties. In order to make the class properties visible to the SwaggerModule, we have to either annotate them with the @ApiProperty() decorator or use a CLI plugin (read more in the Plugin section) which will do it automatically:


import { ApiProperty } from '@nestjs/swagger';

export class CreateCatDto {
  @ApiProperty()
  name: string;

  @ApiProperty()
  age: number;

  @ApiProperty()
  breed: string;
}
Hint Consider using the Swagger plugin (see Plugin section) which will automatically do it for you.

Let's open the browser and verify the generated CreateCatDto model:

In addition, the @ApiProperty() decorator allows setting various Schema Object properties:


@ApiProperty({
  description: 'The age of a cat',
  min: 1,
  default: 1,
})
age: number;
Hint Instead of explicitly typing the @ApiProperty({ required: false }) you can use @ApiPropertyOptional() short-hand decorator.

In order to explicitly set the type of the property, use the type key:


@ApiProperty({
  type: Number,
})
age: number;

Enums#

To identify an enum, we must manually set the enum property on the @ApiProperty with an array of values.


@ApiProperty({ enum: ['Admin', 'Moderator', 'User']})
role: UserRole;

Alternatively, define an actual TypeScript enum as follows:


export enum UserRole {
  Admin = 'Admin',
  Moderator = 'Moderator',
  User = 'User',
}

You can then use the enum directly with the @Query() parameter decorator in combination with the @ApiQuery() decorator.


@ApiQuery({ name: 'role', enum: UserRole })
async filterByRole(@Query('role') role: UserRole = UserRole.User) {}

With isArray set to true, the enum can be selected as a multi-select:

Arrays#

When the property is an array, we must manually indicate the array type as shown below:


@ApiProperty({ type: [String] })
names: string[];

Either include the type as the first element of an array (as shown above) or set the isArray property to true.

Circular dependencies#

When you have circular dependencies between classes, use a lazy function to provide the SwaggerModule with type information:


@ApiProperty({ type: () => Node })
node: Node;

Generics and interfaces#

Since TypeScript does not store metadata about generics or interfaces, when you use them in your DTOs, SwaggerModule may not be able to properly generate model definitions at runtime. For instance, below code won't be correctly inspected by the Swagger module:


createBulk(@Body() usersDto: CreateUserDto[])

In order to overcome this limitation, you can set the type explicitly:


@ApiBody({ type: [CreateUserDto] })
createBulk(@Body() usersDto: CreateUserDto[])

Raw definitions#

In some specific scenarios (e.g. deeply nested arrays, matrices), you may want to describe your type by hand.


@ApiProperty({
  type: 'array',
  items: {
    type: 'array',
    items: {
      type: 'number',
    },
  },
})
coords: number[][];

Likewise, in order to define your input/output content manually in controller classes, use the schema property:


@ApiBody({
  schema: {
    type: 'array',
    items: {
      type: 'array',
      items: {
        type: 'number',
      },
    },
  },
})
async create(@Body() coords: number[][]) {}

Extra models#

In order to define additional models that should be inspected by Swagger module, use the @ApiExtraModels() decorator:


@ApiExtraModels(ExtraModel)
export class CreateCatDto {}

Then, you can get the reference ($ref) to your model using getSchemaPath(ExtraModel):


'application/vnd.api+json': {
   schema: { $ref: getSchemaPath(ExtraModel) },
},

oneOf, anyOf, allOf#

In order to combine schemas, you can use oneOf, anyOf or allOf keywords (read more).


@ApiProperty({
  oneOf: [
    { $ref: getSchemaPath(Cat) },
    { $ref: getSchemaPath(Dog) },
  ],
})
pet: Cat | Dog;
HintgetSchemaPath() function is imported from @nestjs/swagger.

Both Cat and Dog must be defined as extra models using the @ApiExtraModels() decorator (at the class-level).

Multiple specifications#

The SwaggerModule provides a way to support multiple specifications. In other words, you can serve different documentation, with different UIs, on different endpoints.

To support multiple specifications, your application must be written with a modular approach. The createDocument() method takes in a 3rd argument, extraOptions, which is an object with a the property include. The include property has a value which is an array of modules.

You can setup multiple specifications support as shown below:


import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { ApplicationModule } from './app.module';

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

  /**
   * createDocument(application, configurationOptions, extraOptions);
   *
   * createDocument method takes in an optional 3rd argument "extraOptions"
   * which is an object with "include" property where you can pass an Array
   * of Modules that you want to include in that Swagger Specification
   * E.g: CatsModule and DogsModule will have two separate Swagger Specifications which
   * will be exposed on two different SwaggerUI with two different endpoints.
   */

  const options = new DocumentBuilder()
    .setTitle('Cats example')
    .setDescription('The cats API description')
    .setVersion('1.0')
    .addTag('cats')
    .build();

  const catDocument = SwaggerModule.createDocument(app, options, {
    include: [CatsModule],
  });
  SwaggerModule.setup('api/cats', app, catDocument);

  const secondOptions = new DocumentBuilder()
    .setTitle('Dogs example')
    .setDescription('The dogs API description')
    .setVersion('1.0')
    .addTag('dogs')
    .build();

  const dogDocument = SwaggerModule.createDocument(app, secondOptions, {
    include: [DogsModule],
  });
  SwaggerModule.setup('api/dogs', app, dogDocument);

  await app.listen(3000);
}
bootstrap();

Now you can start your server with the following command:


$ npm run start

Navigate to http://localhost:3000/api/cats to see the Swagger UI for cats:

In turn, http://localhost:3000/api/dogs will expose the Swagger UI for dogs:

Tags#

To attach a controller to a specific tag, use the @ApiTags(...tags) decorator.


@ApiTags('cats')
@Controller('cats')
export class CatsController {}

Headers#

To define custom headers that are expected as part of the request, use @ApiHeader().


@ApiHeader({
  name: 'Authorization',
  description: 'Auth token',
})
@Controller('cats')
export class CatsController {}

Responses#

To define a custom HTTP response, we use @ApiResponse() decorator.


@Post()
@ApiResponse({ status: 201, description: 'The record has been successfully created.'})
@ApiResponse({ status: 403, description: 'Forbidden.'})
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}

Nest provides a set of short-hand API response decorators that inherit from the @ApiResponse decorator:

  • @ApiOkResponse()
  • @ApiCreatedResponse()
  • @ApiBadRequestResponse()
  • @ApiUnauthorizedResponse()
  • @ApiNotFoundResponse()
  • @ApiForbiddenResponse()
  • @ApiMethodNotAllowedResponse()
  • @ApiNotAcceptableResponse()
  • @ApiRequestTimeoutResponse()
  • @ApiConflictResponse()
  • @ApiGoneResponse()
  • @ApiPayloadTooLargeResponse()
  • @ApiUnsupportedMediaTypeResponse()
  • @ApiUnprocessableEntityResponse()
  • @ApiInternalServerErrorResponse()
  • @ApiNotImplementedResponse()
  • @ApiBadGatewayResponse()
  • @ApiServiceUnavailableResponse()
  • @ApiGatewayTimeoutResponse()
  • @ApiDefaultResponse()

@Post()
@ApiCreatedResponse({ description: 'The record has been successfully created.'})
@ApiForbiddenResponse({ description: 'Forbidden.'})
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}

To specify a return model for a request, we must create a class and annotate all properties with the @ApiProperty() decorator.


export class Cat {
  @ApiProperty()
  id: number;

  @ApiProperty()
  name: string;

  @ApiProperty()
  age: number;

  @ApiProperty()
  breed: string;
}

Then, Cat model must be used in combination with the type property of the response decorator.


@ApiTags('cats')
@Controller('cats')
export class CatsController {
  @Post()
  @ApiCreatedResponse({
    description: 'The record has been successfully created.',
    type: Cat,
  })
  async create(@Body() createCatDto: CreateCatDto): Promise<Cat> {
    return this.catsService.create(createCatDto);
  }
}

Let's open the browser and verify the generated Cat model:

Global prefix#

To ignore a global prefix for routes set through setGlobalPrefix(), use ignoreGlobalPrefix:


const document = SwaggerModule.createDocument(app, options, {
  ignoreGlobalPrefix: true,
});

Security#

To define which security mechanisms should be used for a specific operation, use the @ApiSecurity() decorator.


@ApiSecurity('basic')
@Controller('cats')
export class CatsController {}

Before you run your application, remember to add the security definition to your base document using DocumentBuilder:


const options = new DocumentBuilder().addSecurity('basic', {
  type: 'http',
  scheme: 'basic',
});

Some of the most popular authentication techniques are predefined (e.g. basic and bearer) and therefore you don't have to define security mechanisms manually as shown above.

Basic authentication#

To enable basic authentication, use @ApiBasicAuth().


@ApiBasicAuth()
@Controller('cats')
export class CatsController {}

Before you run your application, remember to add the security definition to your base document using DocumentBuilder:


const options = new DocumentBuilder().addBasicAuth();

Bearer authentication#

To enable bearer authentication, use @ApiBearerAuth().


@ApiBearerAuth()
@Controller('cats')
export class CatsController {}

Before you run your application, remember to add the security definition to your base document using DocumentBuilder:


const options = new DocumentBuilder().addBearerAuth();

OAuth2 authentication#

To enable OAuth2, use @ApiOAuth2().


@ApiOAuth2(['pets:write'])
@Controller('cats')
export class CatsController {}

Before you run your application, remember to add the security definition to your base document using DocumentBuilder:


const options = new DocumentBuilder().addOAuth2();

File upload#

You can enable file upload for a specific method with the @ApiBody decorator together with @ApiConsumes(). Here's a full example using the File Upload technique:


@UseInterceptors(FileInterceptor('file'))
@ApiConsumes('multipart/form-data')
@ApiBody({
  description: 'List of cats',
  type: FileUploadDto,
})
uploadFile(@UploadedFile() file) {}

Where FileUploadDto is defined as follows:


class FileUploadDto {
  @ApiProperty({ type: 'string', format: 'binary' })
  file: any;
}

Decorators#

All of the available OpenAPI decorators have an Api prefix to distinguish them from the core decorators. Below is a full list of the exported decorators along with a designation of the level at which the decorator may be applied.

@ApiOperation()Method
@ApiResponse()Method / Controller
@ApiProduces()Method / Controller
@ApiConsumes()Method / Controller
@ApiBearerAuth()Method / Controller
@ApiOAuth2()Method / Controller
@ApiBasicAuth()Method / Controller
@ApiSecurity()Method / Controller
@ApiExtraModels()Method / Controller
@ApiBody()Method
@ApiParam()Method
@ApiQuery()Method
@ApiHeader()Method / Controller
@ApiExcludeEndpoint()Method
@ApiTags()Method / Controller
@ApiProperty()Model
@ApiPropertyOptional()Model
@ApiHideProperty()Model

Plugin#

TypeScript's metadata reflection system has several limitations which make it impossible to, for instance, determine what properties a class consists of or recognize whether a given property is optional or required. However, some of these constraints can be addressed at compilation time. Nest provides a plugin that enhances the TypeScript compilation process to reduce the amount of boilerplate code required.

Hint This plugin is opt-in. If you prefer, you can declare all decorators manually, or only specific decorators where you need them.

The Swagger plugin will automatically:

  • annotate all DTO properties with @ApiProperty unless @ApiHideProperty is used
  • set the required property depending on the question mark (e.g. name?: string will set required: false)
  • set the type or enum property depending on the type (supports arrays as well)
  • set the default property based on the assigned default value
  • set several validation rules based on class-validator decorators (if classValidatorShim set to true)
  • add a response decorator to every endpoint with a proper status and type (response model)

Previously, if you wanted to provide an interactive experience with the Swagger UI, you had to duplicate a lot of code to let the package knows how your models/components should be declared in the specification. For example, you could define a simple CreateUserDto class as follows:


export class CreateUserDto {
  @ApiProperty()
  email: string;

  @ApiProperty()
  password: string;

  @ApiProperty({ enum: RoleEnum, default: [], isArray: true })
  roles: RoleEnum[] = [];

  @ApiProperty({ required: false, default: true })
  isEnabled?: boolean = true;
}

While it's not a big deal with medium-sized projects, it becomes pretty verbose & clunky once you have a large set of classes.

Now, with the Swagger plugin enabled, the above class definition can be declared simply:


export class CreateUserDto {
  email: string;
  password: string;
  roles: RoleEnum[] = [];
  isEnabled?: boolean = true;
}

The plugin adds appropriate decorators on the fly based on the Abstract Syntax Tree. Hence, you no longer have to struggle with @ApiProperty decorators scattered throughout the entire project.

Hint The plugin will automatically generate any missing swagger properties, but if you need to override them, you simply set them explicitly via @ApiProperty().

In order to enable the plugin, simply open nest-cli.json (if you use Nest CLI) and add the following plugins configuration:


{
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "plugins": ["@nestjs/swagger/plugin"]
  }
}

You can use the options property to customize the behavior of the plugin.


"plugins": [
  {
    "name": "@nestjs/swagger/plugin",
    "options": {
      "classValidatorShim": false
    }
  }
]

The options property has to fulfill the following interface:


export interface PluginOptions {
  dtoFileNameSuffix?: string[];
  controllerFileNameSuffix?: string[];
  classValidatorShim?: boolean;
}
OptionDefaultDescription
dtoFileNameSuffix['.dto.ts', '.entity.ts']DTO (Data Transfer Object) files suffix
controllerFileNameSuffix.controller.tsController files suffix
classValidatorShimtrueIf set to true, the module will reuse class-validator validation decorators (e.g. @Max(10) will add max: 10 to schema definition)

If you don't use the CLI but instead have a custom webpack configuration, you can use this plugin in combination with ts-loader:


getCustomTransformers: (program: any) => ({
  before: [require('@nestjs/swagger/plugin').before({}, program)]
}),

Migration to 4.0#

If you're currently using @nestjs/swagger@3.*, note the following breaking/API changes in version 4.0.

The following decorators have been changed/renamed:

  • @ApiModelProperty is now @ApiProperty
  • @ApiModelPropertyOptional is now @ApiPropertyOptional
  • @ApiResponseModelProperty is now @ApiResponseProperty
  • @ApiImplicitQuery is now @ApiQuery
  • @ApiImplicitParam is now @ApiParam
  • @ApiImplicitBody is now @ApiBody
  • @ApiImplicitHeader is now @ApiHeader
  • @ApiOperation({ title: 'test' }) is now@ApiOperation({ summary: 'test' })
  • @ApiUseTags is now @ApiTags

DocumentBuilder breaking changes (updated method signatures):

  • addTag
  • addBearerAuth
  • addOAuth2
  • setContactEmail is now setContact
  • setHost has been removed
  • setSchemes has been removed

The following methods have been added:

  • addServer
  • addApiKey
  • addBasicAuth
  • addSecurity
  • addSecurityRequirements

Example#

A working example is available here.

Support us

Nest is an MIT-licensed open source project. It can grow thanks to the support by these awesome people. If you'd like to join them, please read more here.

Principal Sponsor

Sponsors / Partners

Become a sponsor