NodeJS et Swagger
Introduction
Dans ce laboratoire, nous verrons comment intégrer Swagger dans notre API. Swagger permet de décrire les requêtes qu’une API peut recevoir ainsi que ses réponses. L’avantage d’utiliser une telle technologie est qu’elle respecte un standard, ce qui fait qu’il est possible d’utiliser différents outils pour visualiser la documentation.
Swagger ne sert donc pas à documenter votre programme, mais bien les requêtes HTTP de votre API. Dans ce laboratoire nous produirons un fichier au format JSON qui sera ensuite visualisable via différents programmes. Pour ce labo, je vous conseillerais d’utiliser Swagger Editor, qui est un site qui lira votre fichier JSON et affichera une documentation lisible pour les humains : https://editor.swagger.io/

Pré-requis
Ce laboratoire s'appuie sur le laboratoire précédent. Reprenez le code et modifiez-le directement (ou faites une copie si vous désirez garder une copie de chaque laboratoire.)
Intégrer Swagger dans son projet
Il est tout à fait possible d’imaginer faire le fichier JSON à la main. Cependant, la charge de travail risque rapidement de devenir intenable. Pour régler ce problème, il existe des générateurs qui analyseront les commentaires présents dans votre code pour créer ce fichier de documentation. Voici un exemple :

Etant donné qu’il ne s’agit que de commentaires, il faudra faire preuve de rigueur pendant que vous commenterez le code. En effet, votre IDE ne suggèrera aucune recommandation ou correction. Il vous est donc fortement conseillé de tester régulièrement vos modifications !
YAML
Le module qui analysera vos commentaires aura besoin que ceux-ci soient écrits en respectant le format YAML.
Il a l’avantage d’être simple et léger à lire. Ce format semblera familier à ceux qui ont pratiqué du Python.
En effet, tout le YAML se base sur un système d’indentations pour déterminer la hiérarchie des éléments.
Dans l’image précédente, requestBody est le parent de $ref : …, car ce dernier est indenté d’un cran supplémentaire par rapport à son parent.
Si vous désirez en savoir plus, vous pouvez consulter la page Wikipédia : https://fr.wikipedia.org/wiki/YAML
Les composants
Swagger autorise dans sa dernière version d’utiliser les composants. Les composants sont des réponses, schémas, des requêtes, etc qui sont "stockés" pour pouvoir être réutilisés plus tard. Ils sont extrêmement pratiques dès qu’un élément revient plusieurs fois et permet de fractionner la documentation bien plus facilement. La documentation de Swagger donne différents exemples d’utilisations : https://swagger.io/docs/specification/components/
Setup du projet
Votre premier objectif sera de mettre en place ce système de génération de documentation.
Pour cela installez le module swagger-jsdoc en utilisant la commande suivante (remarquez l’option utilisée pour installer le module comme une dépendance de développement):
npm i --save-dev swagger-jsdoc
À la racine de votre projet, créez un dossier swagger. Créez un fichier javascript nommé swagger_jsdoc.js et mettez le code suivant :
import {default as swaggerJSDoc} from "swagger-jsdoc";
import * as fs from "node:fs";
const options = {
definition: {
openapi: "3.0.0",
info: {
title: "API", // Title (required)
version: "1.0.0", // Version (required)
},
},
// Path to the API docs
apis: [
"./controler/**/*.js",
"./middleware/**/*.js",
"./model/**/*.js",
"./routes/**/*.js",
],
};
// Initialize swagger-jsdoc -> returns validated swagger spec in json format
const swaggerSpec = swaggerJSDoc(options);
fs.writeFileSync("./swagger/spec.json", JSON.stringify(swaggerSpec));
La première partie du code sert à donner les informations minimales sur notre API comme son nom et sa version.
La seconde partie sert à indiquer où sont situés les fichiers à analyser pour générer le fichier de documentation Swagger.
Enfin la dernière partie écrit ce fichier dans ./swagger/spec.json.
Notre script de génération est prêt !
L’étape suivante consiste à ajouter ce script convenable dans notre fichier package.json pour pourvoir l’utiliser rapidement et facilement.
Exécutez la commande suivante:
npm pkg set scripts.genDoc="node ./swagger/swagger_jsdoc.js"
Si vous effectuez la commande suivante :
npm run genDoc
Vous devriez avoir votre premier fichier avec la documentation Swagger. Copiez/collez le dans Swagger Editor pour en découvrir le contenu.
Exercice
Essayez de documenter entièrement la partie Produit pour que les routes de l’API soient compréhensibles pour une personne externe.
Dans un premier temps, commencez par documenter la route GET.
Quand vous aurez fini, essayez la route POST.
La documentation est un exercice qui peut être très long, surtout si vous n’êtes pas habitués à en faire. Donnez-vous la moitié du temps du laboratoire pour essayer de réaliser l’exercice. Passez ensuite aux solutions qui vous seront données.
Conclusion
Dans ce laboratoire, vous avez vu comment utiliser Swagger pour documenter votre API. Votre projet devra être entièrement documenté (chaque route, chaque code d’erreur, etc), ce qui prendra un certain temps. Ne vous y prenez donc pas à la dernière minute !
Solutions
Dans cette section, vous aurez les différents commentaires nécessaires pour générer la documentation de l’API du labo. Il sera indiqué quel fichier aura tel commentaire. Vous devrez les placer correctement dans le fichier ! Il est inutile de copier/coller tous les commentaires au début d’un fichier. Même si cela fonctionnera, vous aurez beaucoup de mal à maintenir une telle documentation.
Solutions
/**
* @swagger
* /product:
* post:
* security:
* - bearerAuth: []
* tags:
* - Product
* requestBody:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ProductToAdd'
* responses:
* 201:
* $ref: '#/components/responses/ProductAdded'
* 400:
* description: the error(s) described
* content:
* text/plain:
* schema:
* type: string
* 401:
* $ref: '#/components/responses/UnauthorizedError'
* 500:
* description: Error server
*/
/**
* @swagger
* /product:
* patch:
* security:
* - bearerAuth: []
* tags:
* - Product
* requestBody:
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ProductToUpdate'
* responses:
* 204:
* description: product updated
* 401:
* $ref: '#/components/responses/UnauthorizedError'
* 400:
* description: the error(s) described
* content:
* text/plain:
* schema:
* type: string
* 500:
* description: Error server
*/
/**
* @swagger
* /product/{id}:
* get:
* security:
* - bearerAuth: []
* tags:
* - Product
* parameters:
* - in: path
* name: id
* schema:
* type: integer
* required: true
* description: Numeric ID of the product to get
* responses:
* 200:
* $ref: '#/components/schemas/Product'
* 400:
* description: the error(s) described
* content:
* text/plain:
* schema:
* type: string
* 404:
* description: product not found
* content:
* text/plain:
* schema:
* type: string
* 500:
* description: Error server
*/
/**
* @swagger
* /product/{id}:
* delete:
* security:
* - bearerAuth: []
* tags:
* - Product
* parameters:
* - in: path
* name: id
* schema:
* type: integer
* required: true
* description: Numeric ID of the product to delete
* responses:
* 204:
* description: product deleted
* 400:
* description: the error(s) described
* content:
* text/plain:
* schema:
* type: string
* 401:
* $ref: '#/components/responses/UnauthorizedError'
* 500:
* description: Error server
*/
/**
* @swagger
* components:
* schemas:
* Product:
* type: object
* properties:
* id:
* type: integer
* name:
* type: string
* price:
* type: number
*/
/**
* @swagger
* components:
* responses:
* getProduct:
* description: the product
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Product'
*/
/**
* @swagger
* components:
* responses:
* ProductAdded:
* description: the product
* content:
* application/json:
* schema:
* type: object
* properties:
* id:
* type: integer
*/
/**
* @swagger
* components:
* securitySchemes:
* bearerAuth:
* type: http
* scheme: bearer
* bearerFormat: JWT
* responses:
* UnauthorizedError:
* description: JWT is missing or invalid
* content:
* text/plain:
* schema:
* type: string
*/
/**
* @swagger
* components:
* responses:
* mustBeManager:
* description: the action must be realized by a manager
*/
/**
* @swagger
* components:
* schemas:
* ProductIDSchema:
* type: object
* properties:
* id:
* type: integer
* required:
* - id
*/
/**
* @swagger
* components:
* schemas:
* ProductToAdd:
* type: object
* properties:
* name:
* type: string
* price:
* type: number
* required:
* - name
* - price
*/
/**
* @swagger:
* components:
* schemas:
* ProductToUpdate:
* type: object
* properties:
* id:
* type: integer
* name:
* type: string
* price:
* type: number
* required:
* - id
*/