Aller au contenu

Documentation d'un API avec OpenAPI

La documentation de l'api est une étape essentielle qu'il ne faut pas négliger. Vous devez toujours garder à l'esprit que votre API peut être destiné à être utilisé par d'autres utilisateurs et la documentation va indiquer la marche à suivre.

Votre documentation doit absolument comporter les éléments suivants :

  • Une liste de toutes les routes (endpoint) de votre api avec une description de leur utilité.
  • Les informations d'authentification s'il y a lieu.
  • Pour chaque route, les paramètres à ajouter à la requête.
  • Pour chaque route, toutes les réponses possibles et les valeurs retournées (code de status, données retournées)

Note

Nous allons utiliser la norme OpenAPI pour rédiger la documentation et le module Swagger UI Express pour le rendu visuel.

Installation

Installez le module Swagger UI Express avec npm

npm install swagger-ui-express

Dans le répertoire ./src/config/ créez un fichier JSON qui va contenir votre documentation. Pour l'instant copiez le contenu qui suit, on va voir la composition du fichier en détail plus loin.

./src/config/documentation.json
1
2
3
4
5
6
7
{
    "openapi": "3.1.0",
    "info":{
        "title": "Démo API",
        "version": "1.0.0"
    }
}

Dans le fichier de démarrage de votre application, ajoutez les lignes de codes suivantes (en surligné)

./index.js
import express, { json } from 'express';
import { config } from 'dotenv';
// Importation du module swagger-ui-express
import swaggerUi from 'swagger-ui-express';
// Le fichier qui contient la documentation au format JSON, ajustez selon votre projet
import fs from 'fs';
const swaggerDocument = JSON.parse(fs.readFileSync('./src/config/documentation.json', 'utf8'));

// Options le l'interface, changez le titre "Demo API" pour le nom de votre projet 
const swaggerOptions = {
    customCss: '.swagger-ui .topbar { display: none }',
    customSiteTitle: "Demo API"
};

const app = express();
dotenv.config();

// Middleware
app.use(express.json());

// Routes
// La route à utiliser pour accéder au rendu visuel de la documentation
app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, swaggerOptions));

app.listen(process.env.PORT || 3000, () => {
    console.log(`Le serveur tourne sur le port ${process.env.PORT}`);
});

Maintenant lancez votre application et accédez à la route que vous avez définie (/api/docs si vous avez utilisé le code plus haut). Vous devriez avoir ce résultat.

doc01.png

Résultat de la route /api/docs/

Composition du fichier de documentation

Le fichier JSON sera composé de plusieurs sections, certaines requises et d'autres optionnelles.

À la première ligne, ajoutez la clé openapi avec la version d'OpenAPI que vous utilisez. Vous pouvez utiliser la version 3.1.0

documentation.json
1
2
3
4
5
6
7
8
{
    "openapi" : "3.1.0",
    "info" : { objet info },
    "servers" : [ objet server ],
    "paths" : {
        "route1" : { "method" : objet path }
    }
}

info

L'information générale au sujet de votre api.

documentation.json
    "info" : {
        "title": "Titre de votre API [REQUIS]",
        "summary": "Une courte description de ce que fait votre API",
        "description": "Une description plus détaillé de ce que fait votre API",
        "contact": {
            "name": "API Support",
            "url": "https://www.example.com/support",
            "email": "support@example.com"
        },
        "version": "1.0.1 [REQUIS - Version de votre API]"
    },

servers

Un tableau d'objets serveurs qui indique où on peut exécuter l'api.

documentation.json
    "servers": [
        {
            "url": "http://localhost:3000/",
            "description": "Serveur de développement"
        },
        {
            "url": "http://api.profs.ca",
            "description": "Serveur en ligne"
        }
    ],

paths

Une liste d'objets path qui détaillent les routes de votre api.

documentation.json
{
    "paths" : {
        "route1" : { objet path },
        "route2" : { objet path },
    }
}

Objet path

C'est avec l'objet path qu'on va détailler les routes. On va avoir une clé par route, même si elle est utilisée par plus d'une méthode http. Par exemple si j'ai une route GET /api/salutations et POST /api/salutations je vais ne faire qu'une entrée. Chaque méthode va être définie plus loin.

documentation.json
{
    "paths" : {
        "/api/salutations/liste" : {
            "get": {
                "description": "Retourne la liste de toutes les salutations",
                "summary": "Liste des salutations",
                "tags": [ "Salutions" ],
                "parameters": [ { objet parameter } ],
                "responses": {
                    "200": { response object }
                }
            },
            "post": {
                ...
            }
        }
    }
}

On ne fera pas l'énumération de toutes les options pour détailler une route, à l'essentiel vous devez avoir

  • Une description et un tags
  • La liste des paramètres requis
  • Toutes les réponses possibles detaillées

Pour plus d'information je vous invite à consulter la documentation

Exemple

Voici un exemple avec les routes :

  • GET /api : Retourne un message en HTML
  • GET /api/salutations?langue=fr : Retourne une salutation aléatoire avec un paramètre query optionnel
  • POST /api/salutations : Ajout d'une salutation avec paramètre dans le body.
  • GET /api/salutations/1 : Retourne une salutation selon un id dans la route.
documentation.json
{
    "openapi": "3.1.0",
    "info":{
        "title": "Démo API",
        "version": "1.0.0"
    },
    "servers": [
        {
            "url": "http://localhost:3000/",
            "description": "Serveur de développement"
        },
        {
            "url": "http://api.profs.ca",
            "description": "Serveur en ligne"
        }
    ],
    "paths": {
        "/api": {
            "get": {
                "summary": "Message de bienvenue",
                "tags": ["Accueil"],
                "responses": {
                    "200": {
                        "description": "Retourne un message de bienvenue",
                        "content": {
                            "text/html": {
                                "example": "<h1>Mon premier serveur web sur express !</h1>"
                            }
                        }
                    }
                }
            }
        },
        "/api/salutations": {
            "get": {
                "summary": "Récupérer une salutation aléatoire",
                "tags": ["Salutations"],
                "description": "Récupérer une salutation aléatoire en fonction de la langue d'un code de langue",
                "parameters": [
                    {
                        "in": "query",
                        "name": "langue",
                        "description": "Code souhaité de langue de la salutation. Seulement les codes présent par défaut sont énumérés, d'autres peuvent être présents.",
                        "schema": {
                            "type": "string",
                            "enum": [ "fr", "en", "es", "de" ]
                        },
                        "required": false
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Salutation aléatoire récupérée avec succès",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "code_langue": {
                                            "type": "string",
                                            "example": "fr"
                                        },
                                        "langue": {
                                            "type": "string",
                                            "example": "Français"
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Bonjour le monde"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404" : {
                        "description": "Code de langue non trouvé",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "example": "Erreur, le code de langue [fr] n'existe pas"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "summary": "Ajouter une salutation",
                "tags": ["Salutations"],
                "description": "Ajouter une salutation en fournissant un code de langue, la langue et un message",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "code_langue": {
                                        "type": "string",
                                        "example": "fr"
                                    },
                                    "langue": {
                                        "type": "string",
                                        "example": "Français"
                                    },
                                    "message": {
                                        "type": "string",
                                        "example": "La nouvelle salutation"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Salutation ajoutée avec succésses",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "example": "Salutation ajoutée"
                                        },
                                        "salutation": {
                                            "type": "string",
                                            "example": "La nouvelle salutation"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Erreur de paramètres manquants",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "example": "Erreur, les paramètres code_langue, langue et message sont obligatoires"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "500" : {
                        "description": "Erreur serveur",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "example": "Echec lors de l'ajout de la salutation."
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/salutations/{id}": {
            "get": {
                "summary": "Récupérer une salutation",
                "tags": ["Salutations"],
                "description": "Récupérer une salutation en fonction de son id",
                "parameters": [
                    {
                        "in": "path",
                        "name": "id",
                        "description": "Id de la salutation",
                        "required": true,
                        "schema": {
                            "type": "integer",
                            "format": "int32",
                            "exemple" : "1"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Salutation retrouvée avec succes",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "code_langue": {
                                            "type": "string",
                                            "example": "fr"
                                        },
                                        "langue": {
                                            "type": "string",
                                            "example": "Français"
                                        },
                                        "message": {
                                            "type": "string",
                                            "example": "Bonjour le monde"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404" : {
                        "description": "Salutation non rencontrée",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string",
                                            "example": "Erreur, la salutation [id] n'existe pas"
                                        }
                                    }
                                }   
                            }
                        }
                    }
                }
            }
        }
    }
}

Mediagraphie