Decorators
Which NestJS and @nestjs/swagger decorators nestjs-openapi reads for routing, operations, parameters and security, and which it ignores.
The generator covers the most common NestJS + Swagger decorators. Schemas come from TypeScript types (not @ApiProperty); security schemes are defined in config and decorators add per-operation requirements.
Quick truth table: we read routing + HTTP method decorators, Swagger operation
metadata (tags, operation, consumes/produces, ApiResponse), parameter
descriptions from @ApiParam/@ApiQuery, and method-level exclusion
decorators. We ignore property-level Swagger decorators and response
shortcuts.
For a concise overview, see the Support Matrix.
Routing Decorators
Controller
@Controller('users')
export class UsersController {
// All routes prefixed with /users
}Controller versioning (@Controller({ path: 'users', version: '1' })) is not
currently supported. We only read the string path.
HTTP Method Decorators
Standard HTTP method decorators are supported:
@Controller('users')
export class UsersController {
@Get()
findAll() {}
@Get(':id')
findOne(@Param('id') id: string) {}
@Post()
create(@Body() dto: CreateUserDto) {}
@Put(':id')
replace(@Param('id') id: string, @Body() dto: UpdateUserDto) {}
@Patch(':id')
update(@Param('id') id: string, @Body() dto: PatchUserDto) {}
@Delete(':id')
remove(@Param('id') id: string) {}
}@Options() and @Head() are also supported. @All() is mapped to an all operation, which is not a standard OpenAPI method - prefer explicit verbs if you need strict validation.
Parameter Decorators
@Get(':id')
findOne(
@Param('id') id: string, // Path parameter
@Query('include') include?: string, // Query parameter
@Headers('authorization') auth: string, // Header parameter
) {}
@Post()
create(
@Body() dto: CreateUserDto, // Request body
) {}Response Status
@Post()
@HttpCode(201)
create(@Body() dto: CreateUserDto) {}
@Delete(':id')
@HttpCode(204)
remove(@Param('id') id: string) {}Swagger Decorators
@ApiTags
Assigns tags to controller endpoints:
@ApiTags('users')
@Controller('users')
export class UsersController {
// All endpoints tagged with 'users'
}
// Multiple tags
@ApiTags('users', 'admin')
@Controller('admin/users')
export class AdminUsersController {}@ApiOperation
Describes an operation:
@Get()
@ApiOperation({
summary: 'List all users',
description: 'Returns a paginated list of users',
operationId: 'listUsers',
deprecated: false,
})
findAll() {}| Property | OpenAPI Field |
|---|---|
summary | summary |
description | description |
operationId | operationId |
deprecated | deprecated |
@ApiParam
Documents path parameters:
@Get(':id')
@ApiParam({
name: 'id',
description: 'User ID',
type: String,
required: true,
example: '123e4567-e89b-12d3-a456-426614174000',
})
findOne(@Param('id') id: string) {}@ApiQuery
Documents query parameters:
@Get()
@ApiQuery({
name: 'page',
description: 'Page number',
type: Number,
required: false,
example: 1,
})
@ApiQuery({
name: 'limit',
description: 'Items per page',
type: Number,
required: false,
example: 10,
})
findAll(
@Query('page') page?: number,
@Query('limit') limit?: number,
) {}Query DTOs
When using @Query() without an explicit parameter name, DTO class properties are expanded into individual query parameters by default:
// DTO definition
class PaginationDto {
page?: number;
limit?: number;
}
// Controller
@Get()
findAll(@Query() pagination: PaginationDto) {}
// Generated OpenAPI parameters:
// - page (query, optional)
// - limit (query, optional)This is a common OpenAPI style and works better with code generators. If you prefer to keep the DTO as a single schema reference, set query.style: "ref" in your config. See the Configuration Guide for details.
Explicitly named query params like @Query('filter') filter: FilterDto always
use a schema reference, regardless of the query.style setting.
@ApiBody
Documents the request body:
@Post()
@ApiBody({
description: 'User creation data',
type: CreateUserDto,
required: true,
})
create(@Body() dto: CreateUserDto) {}@ApiResponse
Documents responses. We read status, description, type (including [UserDto] and () => UserDto), isArray and schema (including getSchemaPath()). As in @nestjs/swagger, a declared type or schema wins over the method's return type, and a response without status is the default response.
@Get(':id')
@ApiResponse({
status: 200,
description: 'User found',
type: UserDto,
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'User not found',
})
findOne(@Param('id') id: string) {}Response Shortcuts
Every status shortcut @nestjs/swagger exports is supported (@ApiOkResponse, @ApiCreatedResponse, @ApiNoContentResponse, @ApiBadRequestResponse, @ApiUnauthorizedResponse, @ApiNotFoundResponse, @ApiConflictResponse, @ApiDefaultResponse and the rest), with the same options as @ApiResponse.
Response decorators on the controller apply to every method. A method's own response for the same status wins:
@Controller('users')
@ApiUnauthorizedResponse({ description: 'Missing credentials' })
export class UsersController {
@Get(':id')
@ApiOkResponse({ type: UserDto })
@ApiNotFoundResponse({ description: 'User not found' })
findOne(@Param('id') id: string) {} // 200, 401 and 404
}@ApiConsumes and @ApiProduces
Specify content types:
@Post('upload')
@ApiConsumes('multipart/form-data')
uploadFile(@Body() dto: FileUploadDto) {}
@Get('report')
@ApiProduces('application/pdf')
getReport() {}@ApiExcludeEndpoint and @ApiExcludeController
Exclude endpoints, or every endpoint of a controller, from the generated spec:
@Get('health')
@ApiExcludeEndpoint()
healthCheck() {}To exclude endpoints marked with your own decorators, list them in excludeDecorators.
Custom Decorators
Decorators you build with applyDecorators() are followed automatically, including the arguments they are called with:
export function FilterField(type = FilterDto) {
return applyDecorators(
ApiPropertyOptional({ type }),
IsOptional(),
ValidateNested(),
Type(() => type),
);
}
export const ApiStandardErrors = () =>
applyDecorators(
ApiBadRequestResponse({ type: ErrorDto }),
ApiUnauthorizedResponse(),
);@FilterField() is read as @ApiPropertyOptional({ type: FilterDto }) plus the validation decorators, and @ApiStandardErrors() as its two responses. This works for property, method and controller decorators, for functions and constants, and for wrappers of wrappers.
Some decorators cannot be followed: those from a compiled library, or those that pick decorators with conditions. Describe them with the decorators option.
DTO Schema Generation
Schemas are generated from TypeScript types with
ts-json-schema-generator, then @ApiProperty and class-validator
metadata is applied on top. Metadata is read wherever the class is
declared.
How Schemas Work
The library generates JSON Schema definitions by analyzing TypeScript source files:
// TypeScript types are converted to JSON Schema
export class CreateUserDto {
email: string; // → { "type": "string" }
age?: number; // → { "type": "number" } (optional)
roles: string[]; // → { "type": "array", "items": { "type": "string" } }
}Adding Descriptions with JSDoc
Use JSDoc comments to add descriptions to your schemas:
export class CreateUserDto {
/** User email address */
email: string;
/**
* User age in years
* @minimum 0
* @maximum 150
*/
age?: number;
}class-validator Integration
If you enable extractValidation: true, the library extracts constraints from class-validator decorators:
export class CreateUserDto {
@IsEmail()
email: string; // → { "type": "string", "format": "email" }
@Min(0)
@Max(150)
age?: number; // → { "type": "number", "minimum": 0, "maximum": 150 }
@MinLength(1)
@MaxLength(100)
name: string; // → { "type": "string", "minLength": 1, "maxLength": 100 }
}See the Validation Guide for details.
Property Decorators
@ApiProperty and @ApiPropertyOptional add descriptions, examples, enums, formats, constraints and nullability. required: false and @ApiPropertyOptional() make a property optional even without ?. @ApiHideProperty() removes a property.
A property whose type is another class is a $ref to that class's schema. When the property also has a description or is nullable, it is wrapped as { allOf: [{ $ref }], description } in OpenAPI 3.0, like @nestjs/swagger does, and written as { $ref, description } in 3.1.
Mapped Types
Classes built with PartialType, PickType, OmitType and IntersectionType get the inherited properties with the helpers' rules, including nested helpers such as PartialType(OmitType(UserDto, ['id'])).
Type Inference
The library infers types from TypeScript when possible:
@Controller('users')
export class UsersController {
// Return type inferred from method signature
@Get()
findAll(): Promise<UserDto[]> {
return this.service.findAll();
}
// Parameter types inferred from decorators
@Get(':id')
findOne(@Param('id') id: string): Promise<UserDto> {
return this.service.findOne(id);
}
}For best results, always specify explicit return types on controller methods and use typed DTOs for request bodies.
Security Decorators
Security decorators are fully supported at both controller and method level:
@Controller('users')
@ApiBearerAuth() // Applied to all methods
export class UsersController {
@Get()
findAll() {} // Inherits @ApiBearerAuth
@Get(':id')
@ApiOAuth2(['read:users']) // Method-level override
findOne(@Param('id') id: string) {}
@Delete(':id')
@ApiBearerAuth('jwt')
@ApiSecurity('admin-key') // Multiple schemes (AND logic)
remove(@Param('id') id: string) {}
}Supported Security Decorators
| Decorator | Default Name | Notes |
|---|---|---|
@ApiBearerAuth(name?) | 'bearer' | HTTP Bearer (JWT) |
@ApiBasicAuth(name?) | 'basic' | HTTP Basic auth |
@ApiOAuth2(scopes[], name?) | 'oauth2' | OAuth2 with scopes |
@ApiSecurity(name, scopes?) | - | Generic security scheme |
@ApiCookieAuth(name?) | 'cookie' | Cookie-based auth |
Behavior
- Controller-level: Applies to all methods in the controller
- Method-level: Overrides controller-level security
- Multiple decorators: AND logic (all schemes required)
- Merge with config: Global security from config is merged into per-operation requirements; if both are present, all schemes are required
Security schemes must still be defined in config. Decorators reference scheme
names defined in openapi.security.schemes.
See the Security Guide for complete configuration options.
Next Steps
- Security Guide - Configure authentication schemes
- Validation Guide - Extract class-validator constraints
- Filtering Guide - Exclude endpoints from the spec
Configuration
Every option in the nestjs-openapi config file: output path and format, entry module, tsconfig, OpenAPI info, servers, security schemes and filters.
Support Matrix
What nestjs-openapi supports today: routing decorators, parameters, request bodies, responses, security and versioning, with notes on each.