Une API sans documentation, c'est comme un livre sans sommaire : techniquement utilisable, mais difficile à explorer. Heureusement, NestJS intègre nativement le support de Swagger / OpenAPI via le package @nestjs/swagger. En quelques décorateurs, vous obtenez une documentation interactive, testable depuis le navigateur, et toujours synchronisée avec votre code.
Dans ce tutoriel, nous allons configurer Swagger dans une application NestJS, en nous appuyant sur la configuration réelle du projet Le Murmure des Cartes. Vous apprendrez à structurer la documentation, à décrire vos endpoints, vos DTOs et à publier le tout sur /api/docs.
Prérequis
- Une application NestJS (v10+) fonctionnelle
- Node.js 18 ou supérieur
- Des connaissances de base sur les contrôleurs et DTOs NestJS
1. Installer @nestjs/swagger
La première étape consiste à ajouter le package officiel à votre projet :
npm install --save @nestjs/swaggerCe package fournit à la fois le module qui génère le document OpenAPI et tous les décorateurs (@ApiTags, @ApiOperation, @ApiProperty, etc.) que nous utiliserons pour annoter nos contrôleurs et DTOs.
2. Configurer Swagger dans main.ts
La configuration s'effectue dans le fichier d'amorçage main.ts. L'idée est de construire un objet de configuration via DocumentBuilder, puis de générer le document et de l'exposer sur une route.
Voici la configuration utilisée dans le projet, conditionnée à un environnement non-production :
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api');
if (process.env.NODE_ENV !== 'production') {
const swaggerConfig = new DocumentBuilder()
.setTitle('Le Murmure des Cartes API')
.setDescription('API Backend pour le site de voyance')
.setVersion('1.0')
.setContact(
'Le Murmure des Cartes',
'https://murmure-des-cartes.cloud',
'murmuredescartes@gmail.com',
)
.setLicense('Propriétaire', '')
.addTag('bookings', '📅 Gestion des réservations')
.addTag('contact', '📧 Formulaire de contact')
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
description: 'Entrez votre token JWT',
},
'JWT-auth',
)
.build();
const document = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup('api/docs', app, document);
}
await app.listen(3002);
}
bootstrap();Pourquoi désactiver Swagger en production ? Exposer la structure complète de votre API peut faciliter le travail d'attaquants. Sur des APIs internes ou en développement, c'est un atout. En production, mieux vaut le réserver à un environnement protégé ou le désactiver complètement.
3. Comprendre DocumentBuilder
Le DocumentBuilder suit un pattern fluent : chaque méthode renvoie l'instance, ce qui permet de chaîner les appels. Voici les méthodes principales :
setTitle(): titre affiché en haut de la documentationsetDescription(): description longue, supportant le MarkdownsetVersion(): version de votre API (utile pour le versioning)setContact(name, url, email): informations sur le mainteneursetLicense(name, url): licence d'utilisation de l'APIaddTag(name, description): déclare des catégories d'endpointsaddBearerAuth(): configure l'authentification JWT
Une fois build() appelé, vous obtenez un objet de configuration que SwaggerModule.createDocument() transforme en document OpenAPI complet en scannant tous les contrôleurs de l'application.
4. Personnaliser l'interface Swagger UI
La méthode SwaggerModule.setup() accepte un quatrième argument permettant de personnaliser l'interface. Voici un exemple inspiré du projet :
SwaggerModule.setup('api/docs', app, document, {
customSiteTitle: 'Le Murmure des Cartes API',
customfavIcon: '/favicon.ico',
customCss: `
.swagger-ui .topbar { display: none }
.swagger-ui .info .title { color: #C9A962 }
`,
swaggerOptions: {
persistAuthorization: true,
docExpansion: 'none',
filter: true,
showRequestDuration: true,
},
});L'option persistAuthorization: true est particulièrement pratique : elle conserve le token JWT en cas de rafraîchissement de la page. docExpansion: 'none' replie tous les endpoints au chargement, ce qui rend la navigation plus lisible quand l'API grossit.
5. Organiser les endpoints avec @ApiTags
Le décorateur @ApiTags() regroupe les endpoints d'un contrôleur sous une même catégorie dans Swagger UI. Appliqué au niveau de la classe, il s'applique à toutes les routes :
import { ApiTags } from '@nestjs/swagger';
@ApiTags('contact')
@Controller('contact')
export class ContactController {
// ...
}Les tags référencés ici doivent correspondre à ceux déclarés via addTag() dans le DocumentBuilder pour bénéficier de la description et des emojis.
6. Décrire les endpoints avec @ApiOperation et @ApiResponse
@ApiOperation() fournit un résumé court de la méthode, tandis que @ApiResponse() documente les codes HTTP retournés. Exemple tiré du contrôleur de contact :
@Post()
@Public()
@ApiOperation({ summary: 'Send a contact message' })
@ApiResponse({ status: 201, description: 'Message sent successfully' })
async create(
@Body() createContactDto: CreateContactDto,
): Promise<ApiResponseDto<ContactMessage>> {
const message = await this.contactService.create(createContactDto);
return ApiResponseDto.success(
message,
'Merci pour votre message ! Je vous réponds très vite.',
);
}Vous pouvez bien sûr empiler plusieurs @ApiResponse() pour couvrir les cas d'erreur (400, 404, 500…). Cela aide les consommateurs de l'API à anticiper les comportements.
7. Documenter les paramètres avec @ApiParam et @ApiQuery
Pour les paramètres d'URL et les query strings, deux décorateurs spécifiques existent. Voici un exemple complet issu du contrôleur de réservations :
@Get()
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Get all bookings' })
@ApiQuery({ name: 'status', required: false, enum: BookingStatus })
@ApiQuery({ name: 'startDate', required: false })
@ApiQuery({ name: 'endDate', required: false })
@ApiResponse({ status: 200, description: 'List of bookings' })
async findAll(
@Query('status') status?: BookingStatus,
@Query('startDate') startDate?: string,
@Query('endDate') endDate?: string,
): Promise<ApiResponseDto<Booking[]>> {
const bookings = await this.bookingService.findAll({ status, startDate, endDate });
return ApiResponseDto.success(bookings, 'Bookings retrieved successfully');
}
@Get(':id')
@ApiOperation({ summary: 'Get a specific booking' })
@ApiParam({ name: 'id', description: 'Booking ID' })
@ApiResponse({ status: 200, description: 'Booking details' })
async findOne(@Param('id', ParseUUIDPipe) id: string) {
// ...
}L'option enum: BookingStatus est précieuse : Swagger UI propose alors un menu déroulant avec les valeurs valides, ce qui réduit considérablement les erreurs de saisie lors des tests manuels.
8. Documenter les DTOs avec @ApiProperty
Les DTOs décrivent la forme des données entrantes et sortantes. Le décorateur @ApiProperty() enrichit chaque champ d'informations exploitées par Swagger :
import { ApiProperty } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, MaxLength } from 'class-validator';
export class CreateContactDto {
@ApiProperty({
description: 'Nom complet de l\'expéditeur',
example: 'Marie Dupont',
maxLength: 100,
})
@IsNotEmpty()
@MaxLength(100)
name: string;
@ApiProperty({
description: 'Adresse email de contact',
example: 'marie.dupont@example.com',
})
@IsEmail()
email: string;
@ApiProperty({
description: 'Contenu du message',
example: 'Bonjour, je souhaite réserver une guidance...',
})
@IsNotEmpty()
@MaxLength(2000)
message: string;
}Pour les champs optionnels, utilisez @ApiPropertyOptional() ou @ApiProperty({ required: false }). Vous pouvez également préciser type, enum, format (par exemple 'date-time' ou 'uuid') selon les besoins.
9. Accéder à la documentation
Une fois l'application démarrée, ouvrez votre navigateur à l'adresse :
http://localhost:3002/api/docsVous y verrez tous les endpoints, regroupés par tags, avec la possibilité d'envoyer des requêtes directement depuis l'interface. Si vous avez configuré addBearerAuth(), un bouton Authorize permet de saisir un token JWT qui sera automatiquement injecté dans les requêtes.
Bonnes pratiques
- Utilisez le plugin CLI Swagger : configuré dans
nest-cli.json, il génère automatiquement les@ApiPropertyà partir des types TypeScript et limite la verbosité - Documentez les erreurs : un endpoint sans
@ApiResponse({ status: 400 })ou404est incomplet - Fournissez des exemples : un
examplebien choisi vaut mieux qu'une longue description - Désactivez Swagger en production ou protégez-le par authentification
- Versionnez votre API et mettez à jour
setVersion()à chaque release majeure
Conclusion
Avec @nestjs/swagger, vous obtenez en quelques minutes une documentation OpenAPI complète, interactive et toujours à jour. Les décorateurs @ApiTags, @ApiOperation, @ApiResponse, @ApiParam, @ApiQuery et @ApiProperty couvrent l'essentiel des besoins, tandis que DocumentBuilder centralise les métadonnées globales de l'API.
Pour aller plus loin, explorez le plugin CLI qui automatise la majorité des annotations, l'export du document JSON pour générer des clients TypeScript ou Dart, ou encore l'intégration avec des outils comme Redoc pour une documentation publique élégante.




Commentaires