Quelqu’un aime écrire de la documentation ? Moi non ! Cependant, il est indiscutable qu’il est nécessaire d’avoir une bonne documentation de nos API afin de faciliter la vie des autres développeurs et des entreprises qui souhaitent ou doivent s’intégrer à notre backend, n’est-ce pas ? Et s’il existait une manière, en plus de documenter nos API, de proposer une interface utilisateur conviviale pour les tester facilement dans le navigateur ?
C’est en pensant à cela que l’entreprise SmartBear, en 2011, a créé Swagger, un ensemble d’outils pour le développement, la documentation et les tests d’API qui, par la suite, deviendrait la spécification OpenAPI, réunissant des noms comme Microsoft, IBM et d’autres géants. Aujourd’hui, Swagger demeure synonyme de standardisation dans la documentation des API, mais il convient de souligner qu’il existe de nombreux outils sur le marché qui adoptent l’OpenAPI, et il est important de différencier tooling (Swagger) de spécification (OpenAPI).
Dans ce tutoriel, nous allons voir comment utiliser Swagger dans une application backend Node.js + Express afin, grâce à la spécification OpenAPI, de générer une documentation en ligne et testable d’une API fictive de clients, mais que vous pouvez facilement adapter à d’autres scénarios, y compris l’authentification, un cas d’usage courant dans les API.
Si vous préférez, vous pouvez regarder la vidéo ci-dessous plutôt que de lire le tutoriel.
Allons-y !
#1 – Le projet
Comme base pour documenter avec Swagger, je vais utiliser un autre projet ici du site où j’ai enseigné l’implémentation de l’authentification JWT dans une application Node.js avec Express, disponible sur mon GitHub. Il est assez simple et le fichier principal, index.js, que je reproduis ci-dessous avec une légère modification, où j’ai extrait les routes dans un fichier séparé pour des raisons d’organisation.
//index.js
import "dotenv/config";
import express from "express";
const app = express();
app.use(express.json());
import router from "./routes.js";
app.use(router);
app.listen(3000, () => {
console.log("Servidor escutando na porta 3000...");
});
À présent, le fichier de routes (routes.js) s’est organisé de la manière suivante :
import jwt from "jsonwebtoken";
import express from "express";
const router = express.Router();
router.get("https://imasters.com.br/", (req, res, next) => {
res.json({ message: "Tudo ok por aqui!" });
})
router.get("/clientes", verifyJWT, (req, res) => {
console.log("Retornou todos clientes!");
res.json([{ id: 1, nome: "luiz" }]);
})
function verifyJWT(req, res, next) {
let token = req.headers["authorization"];
if (!token) return res.status(401).json({ message: "No token provided." });
token = req.headers["authorization"].replace("Bearer ", "");
if (blacklist[token]) return res.status(403).json({ message: "Invalid token." });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
if (!decoded) return res.status(403).json({ message: "Invalid token." });
res.locals.token = decoded;
return next();
} catch (err) {
return res.status(403).json({ message: err.message });
}
}
router.post("/login", (req, res, next) => {
//esse teste abaixo deve ser feito no seu banco de dados
if (req.body.user === "luiz" && req.body.password === "123") {
//auth ok
const userId = 1; //esse id viria do banco de dados
const token = jwt.sign({ userId }, process.env.JWT_SECRET, {
expiresIn: parseInt(process.env.JWT_EXPIRES)
});
return res.json({ token: token });
}
res.status(401).json({ message: "Invalid credentials!" });
})
La première étape pour préparer ce projet à l’utilisation de Swagger consiste à installer les dépendances. Il n’en existe qu’une seule réellement nécessaire, mais j’en installerai deux car la seconde facilite grandement l’utilisation de Swagger à mon avis.
npm install swagger-ui-express swagger-jsdoc
Les paquets que nous installons sont :
- Swagger UI Express: Swagger lui-même, qui fournira une interface utilisateur web pour notre documentation et nos tests;
- Swagger JSDoc: la bibliothèque qui va générer la documentation pour nous partir de commentaires du type JSDoc, suivant la spécification OpenAPI;
Sans Swagger JSDoc, nous aurions dû créer des fichiers JSON ou YAML séparés du code pour définir toute la spécification. Mais avec lui, nous utilisons seulement des blocs de commentaires JSDoc au-dessus de chaque endpoint et la documentation sera extraite à partir de ces blocs.
Maintenant, allons importer ces deux paquets en haut du index.js :
import swaggerUI from "swagger-ui-express";
import swaggerJsdoc from "swagger-jsdoc";
Et par la suite, nous allons configurer Swagger JSDoc comme ci-dessous, j’explique ensuite :
const openapiSpecification = swaggerJsdoc({
definition: {
openapi: '3.0.0',
info: {
title: 'Clients API',
version: '1.0.0',
},
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
},
}
},
apis: ['./routes.js'],
});
Ici, j’indique deux choses principales : le standard que nous allons utiliser et où se trouvent mes API dans le projet.
Le standard que j’utilise ici est OpenAPI 3, où dans la propriété info je précise le nom de mon API et sa version, des informations utiles qui apparaîtront ensuite dans l’interface Swagger. Déjà dans components, je déclare le schéma de sécurité utilisé par cette API (Bearer Auth avec JWT). Cette information sera utilisée ensuite pour que les tests des routes authentifiées fonctionnent via l’interface.
Enfin, il faut maintenant injecter Swagger en tant que middleware dans Express, en passant nos configurations comme ci-dessous.
app.use("/docs", swaggerUI.serve, swaggerUI.setup(openapiSpecification));
Avec cela, j’ai créé une route docs où Swagger UI sera disponible pour être consultée dans le navigateur; pour l’instant, c’est pratiquement vide, car nous n’avons pas encore écrit les JSDocs sur les endpoints.

#2 – Première Documentation
Commençons à documenter nos endpoints à partir des routes publiques, car elles sont plus simples. La plus basique de toutes est notre route de Health Check, une simple requête GET qui indique si le serveur est opérationnel, voici :
router.get("https://imasters.com.br/", (req, res, next) => {
res.json({ message: "Tudo ok por aqui!" });
})
Pour documenter cette route, ouvrez un bloc JSDoc au-dessus avec le modèle YAML, indiquant le schéma @openapi, confirmant l’endpoint comme “/”, le verbe comme “get” et fournissant quelques propriétés que je détaille ci-après. Faites simplement attention à l’indentation, elle est importante dans le format YAML car elle dénote la hiérarchie des informations et de la portée, comme les clés du JS :
/**
* @openapi
* /:
* get:
* summary: Health Check
* description: Returns the health status of the server
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
*/
- summary: ici, vous indiquez le titre de l’endpoint ;
- description: ici se trouve la description de cet endpoint (à quoi il sert) ;
- responses: ici nous avons les réponses possibles pour un appel HTTP sur cet endpoint, il est courant d’avoir au moins la réponse 200 mais il peut aussi y avoir d’autres codes qui peuvent être retournés, comme nous le verrons plus tard ;
Pour chaque réponse, nous avons la description de la réponse elle-même et son contenu (content). Généralement dans les API REST, le content sera application/json comme dans mon exemple et le schéma varie selon le retour, si vous en avez un. Personnellement, j’utilise GitHub Copilot pour m’aider à écrire ces documentations de schéma, car il comprend rapidement ce qu’il faut mettre comme schéma en se basant sur le code de l’endpoint lui-même, je le recommande fortement, c’est gratuit.
Si vous lancez votre projet et que vous êtes nouveau, vous verrez maintenant qu’un endpoint est documenté et peut être testé.

Passez une minute pour regarder tous les détails de cette UI et comprendre son lien avec le JSDoc que nous avons rédigé. À la fin, le bouton “Try it out” vous permet de tester cette route et de vérifier son fonctionnement.

Comme cette route n’a pas de paramètres, le test est très direct et le retour est également simple, mais cela vaut le coup de prendre une minute pour regarder et vérifier que tout est correct comme prévu. Regardez la commande CURL utilisée pour le test et le corps de la réponse.
Avec cela, nous avons terminé une première utilisation de Swagger. Maintenant, nous pouvons avancer plus rapidement sur les autres endpoints.
#3 – Authentification
Nous allons créer un autre endpoint public, mais qui nous permettra ensuite de tester les privés. L’endpoint de connexion est très simple et présente une authentification factice facile à tester dans cet exemple.
router.post("/login", (req, res, next) => {
//esse teste abaixo deve ser feito no seu banco de dados
if (req.body.user === "luiz" && req.body.password === "123") {
//auth ok
const userId = 1; //esse id viria do banco de dados
const token = jwt.sign({ userId }, process.env.JWT_SECRET, {
expiresIn: parseInt(process.env.JWT_EXPIRES)
});
return res.json({ token: token });
}
res.status(401).json({ message: "Invalid credentials!" });
})
Pour le documenter, faites attention au changement d’endpoint (/login) et au verbe (post) qui exige un corps de requête avec les données d’authentification. Notez aussi que nous avons maintenant deux réponses possibles (200 et 401) selon le succès de l’authentification. Les autres champs n’apportent pas grand-chose ici, vous verrez rapidement que c’est un travail assez répétitif, c’est pourquoi je répète le conseil d’utiliser GitHub Copilot pour vous aider à accélérer ce processus.
/**
* @openapi
* /login:
* post:
* summary: User login
* description: Authenticates a user and returns a JWT token
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* user:
* type: string
* password:
* type: string
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* type: object
* properties:
* token:
* type: string
* 401:
* description: Invalid credentials
*/
Enregistrez et ouvrez dans le navigateur et testez cette route en indiquant d’abord des identifiants invalides pour voir le 401, puis les identifiants corrects (luiz et 123) pour obtenir le token.

Remarquez que dans le corps de la réponse vous allez recevoir le JWT. Copiez son contenu car nous devons autoriser les prochaines requêtes privées. Ce JWT doit être renseigné dans le champ Authorize qui a été créé dans le coin supérieur droit de Swagger en raison de nos configurations.

Une fois autorisés, les requêtes qui doivent envoyer le jeton utiliseront ces informations que vous avez renseignées, comme vous le verrez ci-après.
#4 – Routes privées
Maintenant que nous avons appris l’authentification via Swagger, nous pouvons documenter les routes privées. Tout d’abord celle qui liste les clients, dont la route est reproduite ci-dessous :
router.get("/clientes", verifyJWT, (req, res) => {
console.log("Retornou todos clientes!");
res.json([{ id: 1, nome: "luiz" }]);
})
Et sa documentation ensuite :
/**
* @openapi
* /clientes:
* get:
* summary: Get all clients
* description: Returns a list of clients
* security:
* - bearerAuth: []
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* type: array
* items:
* type: object
* properties:
* id:
* type: integer
* nome:
* type: string
* 401:
* description: Unauthorized
*/
La seule nouveauté ici, en plus d’une réponse avec un schéma plus élaboré puisqu’il s’agit d’un tableau d’éléments, est la propriété security en haut, indiquant que cette requête doit être authentifiée. Cela va inclure dans les tests Swagger le JWT que vous avez renseigné dans le champ Authorize de l’interface.
Pour terminer, voici l’endpoint de déconnexion ci-dessous :
router.post("/logout", verifyJWT, (req, res) => {
const token = req.headers["authorization"].replace("Bearer ", "");
blacklist[token] = true;
setTimeout(() => delete blacklist[token], parseInt(process.env.JWT_EXPIRES) * 1000);
res.json({ token: null });
})
Avec la documentation suivante :
/**
* @openapi
* /logout:
* post:
* summary: User logout
* description: Logs out a user and invalidates the JWT token
* security:
* - bearerAuth: []
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* type: object
* properties:
* token:
* type: string
* nullable: true
* 401:
* description: Unauthorized
*/
Zero nouveautés ici, car le schéma de sécurité est le même que précédemment. Avec toutes les documentations en place, notre Swagger UI est complète, comme vous pouvez le voir sur l’image ci-dessous. Remarquez les icônes de cadenas sur la droite, indiquant quelles routes sont privées.

Avec cela se termine ce tutoriel sur Swagger.
À la prochaine !




