Desarrollador de software, con experiencia en desarrollo web y móvil. Apasionado por la tecnología y la innovación.
El primer paso que debemos ejecutar es la instalación de el paquete swagger en nuestro proyecto, si usamos npm ejecutamos la siguiente instrucción:
npm install --save @nestjs/swagger
En caso de usar yarn ejecutamos la siguiente acción:
yarn add @nestjs/swagger
Una vez instalada el paquete swagger vamos a ir al archivo main.ts y agregamos la siguiente configuración:
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('Blog API')
.setDescription('The blog API description')
.setVersion('1.0')
.addTag('blog')
.build();
const documentFactory = () => SwaggerModule.createDocument(app, config);
SwaggerModule.setup('docs', app, documentFactory, {
jsonDocumentUrl: '/swagger-json',
});
...
}
await bootstrap();
En el fragmento anterior agregamos el módulo SwaggerModule a nuestra aplicación y al mismo tiempo creamos un documento de OpenAPI que puede ser accedido en la ruta docs. Adicionalmente, configuramos la ruta swagger-json para exponer la documentación generada por Swagger en formato JSON para que pueda ser consumido por modelos de IA o herramientas automatizadas.
Para documentar los atributos de un DTO tenemos algunos decoradores muy útiles, como, por ejemplo:
@ApiProperty()@ApiPropertyOptional()Estos decoradores vienen del paquete @nestjs/swagger. Como el nombre indica uno se usa cuando la propiedad es requerida y el otro cuando es opcional.
Estos decoradores reciben un objeto de configuración que puede contener los siguientes atributos:
description: Una breve descripción del atributo.default: Indica el valor por defecto.minimum o maximum: El valor mínimo o máximo que puede tomar.type: Indica explícitamente el tipo de dato. Si es un array type: [tipo nativo].maxLength o minLength: Indica la longitud máxima y mínima.enum: Si el atributo es un enum, pasamos un array con los elementos.example: Permite indicar un ejemplo del contenido del atributo.examples: Permite indicar varios ejemplos para el atributo.Entre otras posibles configuraciones, es posible profundizar más en estos decoradores en la documentación oficial de NestJS para Swagger.
Para los DTO de tipo Update, aquellos que se derivan de DTOs definidos completamente a los que se aplica el mapped type PartialType, debemos mantenerlos como fueron definidos, pero ahora el paquete se debe importar desde @nestjs/swagger que se encarga de agregar el decorador @ApiPropertyOptional() internamente.
Un ejemplo de un UpdateDTO se muestra a continuación:
import { PartialType } from "@nestjs/swagger";
import { CreatePostDto } from "./create-post.dto";
export class UpdatePostDto extends PartialType(CreatePostDto) {}
Como ya sabemos los endpoints son gestionados desde los controladores, por lo tanto, vamos a ver los decoradores y parámetros que debemos usar en un controller con el fin de generar una buena documentación.
Para un endpoint podemos hacer uso del decorador @ApiOperation() y pasar los siguientes atributos en el objeto de configuración:
summary: Un resumen de la operación realizada por el endpoint.description: Una descripción detallada de la operación realizada por el endpoint.deprecated: Una opción booleana que indica visualmente que el endpoint está deprecado.Un ejemplo de los anterior es:
@ApiOperation({
summary: 'Get all users',
description: 'Retrieve a list of all users registered in the system',
deprecated: true
})
@Get()
getUsers() {
return this.userService.getUsers();
}
Podemos describir posibles respuestas de nuestro endpoint mediante el decorador @ApiResponse() que puede recibir los siguiente atributos en su objeto de configuración:
status: El valor numérico del código de respuesta HTTP.description: Una descripción de la respuesta entregada.type: Una clase decorada que indica los atributos de la respuesta.isArray: Un valor booleano que indica si la respuesta corresponde a un array.Un ejemplo de la descripción de respuestas se muestra a continuación:
export class UsersController {
@Get()
@ApiResponse({
status: 200,
description: "The users have been successfully retrieved.",
type: UserDto,
isArray: true,
})
findAll() {
return [];
}
}
También es importante mencionar que NestJS nos ofrece una gran lista de API responses predefinidas que nos pueden ahorrar mucho tiempo, una parte de la lista se muestra a continuación:
@ApiOkResponse()@ApiCreatedResponse()@ApiAcceptedResponse()@ApiNoContentResponse()@ApiMovedPermanentlyResponse()@ApiFoundResponse()@ApiBadRequestResponse()@ApiUnauthorizedResponse()@ApiNotFoundResponse()@ApiForbiddenResponse()@ApiMethodNotAllowedResponse()@ApiNotAcceptableResponse()@ApiRequestTimeoutResponse()@ApiConflictResponse()@ApiPreconditionFailedResponse()@ApiTooManyRequestsResponse()@ApiGoneResponse()@ApiPayloadTooLargeResponse()@ApiUnsupportedMediaTypeResponse()@ApiUnprocessableEntityResponse()@ApiInternalServerErrorResponse()@ApiNotImplementedResponse()@ApiBadGatewayResponse()@ApiServiceUnavailableResponse()@ApiGatewayTimeoutResponse()@ApiDefaultResponse()Un ejemplo que muestra el uso de los decoradores predefinidos se muestra a continuación:
@Post()
@ApiCreatedResponse({ description: 'The record has been successfully created.'})
@ApiForbiddenResponse({ description: 'Forbidden.'})
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
To document query and route parameters in NestJS, you use the @ApiParam() and @ApiQuery() decorators from the @nestjs/swagger package.Here is a complete example showing how to implement both alongside your route handlers:
import { Controller, Get, Param, Query } from ‘@nestjs/common’; import { ApiOperation, ApiParam, ApiQuery, ApiTags } from ‘@nestjs/swagger’;
@ApiTags(‘products’) @Controller(‘products’) export class ProductsController {
@Get(‘:id’)
@ApiOperation({ summary: ‘Get a product by ID’ })
// 1. Documenting a Route/Path Parameter
@ApiParam({
name: ‘id’,
type: String,
description: ‘The unique identifier of the product’,
example: ‘prod_95x82103’,
})
findOne(@Param(‘id’) id: string) {
return This action returns product #${id};
}
@Get()
@ApiOperation({ summary: ‘List all products with pagination’ })
// 2. Documenting individual Query Parameters
@ApiQuery({
name: ‘limit’,
type: Number,
required: false,
description: ‘Number of items to return per page’,
example: 10,
})
@ApiQuery({
name: ‘search’,
type: String,
required: false,
description: ‘Filter products by name or description’,
})
findAll(@Query(‘limit’) limit?: number, @Query(‘search’) search?: string) {
return Returns products filtered by "${search}", limited to ${limit} items.;
}
}
Pro-Tip: Documenting a Query DTOIf you have a lot of query parameters, it is much cleaner to group them into a class (Data Transfer Object) and use the @ApiProperty() decorator inside that class. Swagger will automatically pick them up without cluttering your controller:
// products-query.dto.ts import { ApiPropertyOptional } from ‘@nestjs/swagger’;
export class ProductsQueryDto { @ApiPropertyOptional({ description: ‘Number of items to return’, example: 10 }) limit?: number;
@ApiPropertyOptional({ description: ‘Filter products by name’ }) search?: string; }
// In your controller: @Get() findAll(@Query() query: ProductsQueryDto) { // Swagger automatically documents ‘limit’ and ‘search’ here! }