Swagger UI est l'outil de documentation interactive le plus utilisé dans l'écosystème NestJS. Par défaut, il fournit une interface fonctionnelle mais générique. Pourtant, avec quelques options bien choisies, il est possible de transformer cette page en un véritable portail développeur, à l'image du projet et de sa charte graphique. Dans ce tutoriel, nous allons voir comment personnaliser Swagger UI en profondeur dans une application NestJS : titre, favicon, CSS, authentification Bearer, options d'UX et export OpenAPI.
Nous nous appuierons sur des exemples concrets issus du backend du site Le Murmure des Cartes, une API NestJS qui expose des endpoints de réservation, paiement Stripe et gestion de contenu.
Prérequis
- Une application NestJS 10+ opérationnelle
- Le package
@nestjs/swaggerinstallé - Quelques contrôleurs déjà décorés avec
@ApiTags,@ApiOperation, etc.
npm install --save @nestjs/swagger
Configuration de base avec DocumentBuilder
Tout commence dans le fichier main.ts. Le DocumentBuilder permet de configurer les métadonnées globales de la documentation : titre, description, version, contact, licence et tags. C'est aussi à ce niveau qu'on désactive Swagger en production pour des raisons de sécurité.
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
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', '')
.build();
const document = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup('api/docs', app, document);
}
À ce stade, la documentation est accessible sur /api/docs, mais elle ressemble encore à toutes les autres. Passons à la personnalisation.
Grouper les endpoints par tags avec des icônes
Les tags permettent de regrouper logiquement les endpoints par domaine fonctionnel. L'astuce peu connue : on peut intégrer des emojis directement dans les noms de tags pour gagner en lisibilité visuelle.
const swaggerConfig = new DocumentBuilder()
.setTitle('Le Murmure des Cartes API')
.setVersion('1.0')
.addTag('health', '🏥 Vérification de l\'état de l\'API')
.addTag('services', '✨ Gestion des services de guidance')
.addTag('bookings', '📅 Gestion des réservations')
.addTag('payment', '💳 Paiements Stripe')
.addTag('contact', '📧 Formulaire de contact')
.addTag('oracles', '🔮 Gestion des oracles et tarots')
.addTag('testimonials', '⭐ Témoignages clients')
.addTag('content', '📝 Contenu dynamique du site')
.addTag('upload', '📤 Upload de fichiers')
.build();
Côté contrôleur, il suffit d'utiliser le décorateur @ApiTags avec le nom correspondant :
@ApiTags('bookings')
@Controller('bookings')
export class BookingController {
// ...
}
Ajouter l'authentification Bearer (JWT)
La majorité des APIs modernes utilisent un token JWT pour authentifier les requêtes. Swagger permet de tester ces endpoints protégés directement depuis l'interface, à condition de déclarer le schéma de sécurité.
const swaggerConfig = new DocumentBuilder()
// ... autres options
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
description: 'Entrez votre token JWT',
},
'JWT-auth', // nom de référence du schéma
)
.build();
Le second argument ('JWT-auth') est un identifiant qu'on réutilisera dans les contrôleurs pour indiquer quels endpoints requièrent une authentification.
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
@ApiTags('bookings')
@ApiBearerAuth('JWT-auth')
@Controller('bookings')
export class BookingController {
@Get('stats')
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Get booking statistics' })
async getStats(): Promise<ApiResponseDto<any>> {
// Endpoint protégé : un cadenas apparaît dans Swagger
}
}
Une fois l'authentification déclarée, un bouton Authorize apparaît en haut de la page Swagger. L'utilisateur saisit son token, et il sera automatiquement injecté dans le header Authorization de chaque requête testée.
Personnaliser les couleurs et l'apparence avec customCss
L'option customCss de SwaggerModule.setup() accepte une chaîne CSS qui sera injectée dans la page. C'est l'occasion d'aligner Swagger avec la charte graphique de votre projet : on cache la barre supérieure officielle, on change la couleur du titre, et on personnalise les couleurs des verbes HTTP.
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 }
.swagger-ui .info .description { font-size: 14px }
.swagger-ui .opblock-tag {
font-size: 16px;
border-bottom: 1px solid #C9A962
}
.swagger-ui .opblock.opblock-get .opblock-summary-method { background: #6B5B7A }
.swagger-ui .opblock.opblock-post .opblock-summary-method { background: #C9A962 }
.swagger-ui .opblock.opblock-patch .opblock-summary-method { background: #49cc90 }
.swagger-ui .opblock.opblock-delete .opblock-summary-method { background: #f93e3e }
`,
});
Trois options complémentaires sont importantes :
- customSiteTitle : modifie le titre affiché dans l'onglet du navigateur
- customfavIcon : change le favicon (notez la casse particulière, sans majuscule à "fav")
- customCss : injecte du CSS pour repeindre l'interface
Pour les CSS plus volumineux, vous pouvez utiliser customCssUrl et pointer vers un fichier statique servi par votre application.
Améliorer l'UX avec swaggerOptions
Le bloc swaggerOptions donne accès aux paramètres natifs de Swagger UI. Voici les plus utiles au quotidien :
SwaggerModule.setup('api/docs', app, document, {
// ... customCss, etc.
swaggerOptions: {
persistAuthorization: true, // conserve le token JWT après un refresh
docExpansion: 'none', // tous les endpoints repliés au démarrage
filter: true, // active la barre de recherche
showRequestDuration: true, // affiche le temps de réponse
syntaxHighlight: {
activate: true,
theme: 'monokai',
},
},
});
Détails de ces options :
- persistAuthorization : indispensable pour ne pas avoir à re-saisir son token à chaque rafraîchissement
- docExpansion :
'none'(tout fermé),'list'(tags ouverts) ou'full'(tout ouvert) - filter : ajoute une barre de recherche pour filtrer les endpoints — précieux sur les grosses APIs
- showRequestDuration : affiche le temps de réponse, utile pour le debug en local
Masquer certains endpoints de la documentation
Tous les endpoints n'ont pas vocation à apparaître dans la documentation publique. Les webhooks Stripe, les routes internes ou les endpoints de debug doivent souvent rester invisibles. Le décorateur @ApiExcludeEndpoint() (ou @ApiExcludeController() pour un contrôleur entier) règle le problème :
import { ApiExcludeEndpoint } from '@nestjs/swagger';
@Controller('webhooks')
export class WebhooksController {
@Post('stripe')
@ApiExcludeEndpoint() // n'apparaît pas dans Swagger
async handleStripeWebhook(@Req() req: RawBodyRequest<Request>) {
// ...
}
}
Documenter finement les DTOs
Pour que Swagger affiche correctement les corps de requête, chaque propriété de DTO doit être annotée avec @ApiProperty. Cela permet aussi de documenter les contraintes de validation déjà appliquées par class-validator :
import { ApiProperty } from '@nestjs/swagger';
import { IsUUID, IsEmail, IsNotEmpty, MaxLength } from 'class-validator';
export class CreateCheckoutDto {
@ApiProperty({ description: 'Service ID' })
@IsUUID()
@IsNotEmpty()
serviceId: string;
@ApiProperty({ description: 'Customer email' })
@IsEmail()
@IsNotEmpty()
@MaxLength(254)
email: string;
@ApiProperty({ description: 'Question(s) for written guidance', required: false })
@IsString()
@IsOptional()
@MaxLength(5000)
question?: string;
}
De la même façon, on documentera les réponses standards. Le pattern ApiResponseDto<T> utilisé dans le projet expose success, message et data de manière homogène, ce qui rend la documentation prévisible pour les consommateurs de l'API.
Exporter la spécification OpenAPI
Une fois Swagger configuré, NestJS expose automatiquement la spécification OpenAPI au format JSON sur l'URL /api/docs-json (le suffixe -json est ajouté au chemin défini dans setup()).
# Récupérer la spec
curl http://localhost:3002/api/docs-json -o openapi.json
Ce fichier peut ensuite être importé dans des outils tiers :
- Postman : Import > OpenAPI, génère automatiquement une collection complète
- Insomnia : Create > Import From > File avec le JSON
- Génération de clients : avec
openapi-generatorouopenapi-typescriptpour produire des SDK TypeScript, Java, etc.
Pour automatiser la génération en CI/CD, on peut ajouter un script qui démarre l'app, récupère la spec et l'archive comme artefact :
npm run build
node -e "require('./dist/main')" &
sleep 5
curl http://localhost:3002/api/docs-json -o openapi.json
Conclusion
En quelques options bien dosées, Swagger UI passe d'une page générique à un véritable portail développeur cohérent avec votre projet. Vous avez vu comment :
- Structurer la documentation avec
DocumentBuilder, des tags et des icônes - Sécuriser les tests d'API via
addBearerAuth()et@ApiBearerAuth() - Personnaliser l'apparence avec
customCss,customSiteTitleetcustomfavIcon - Améliorer l'UX avec
persistAuthorization,filteretdocExpansion - Masquer les endpoints sensibles avec
@ApiExcludeEndpoint() - Exporter la spec OpenAPI pour Postman, Insomnia ou la génération de SDK
Pour aller plus loin, explorez les décorateurs @ApiExtraModels, @ApiOkResponse avec génériques, ou encore nestjs-zod pour générer la documentation à partir de schémas Zod. Et n'oubliez jamais de désactiver Swagger en production pour ne pas exposer la surface d'attaque de votre API.




Commentaires