Shiro's blog

Comment documenter ses APIs python ?

Translations: en

Introduction

Le Sphinx
Je sens qu'il manque de la documentation dans ce projet. — Le Sphinx

La documentation est souvent vue par les développeurs comme une corvée. Mais elle est pourtant une part essentielle d'un projet. Sans documentation, les utilisateurs font face à une multitude d'obstacles malgré parfois un intérêt palpable pour le projet.

Dans le cadre d'une API, que ce soit interne à une entreprise ou dans le monde libre, cela veut dire que les développeurs voulant s'interfacer avec votre API n'ont guère d'autre moyen que de lire le code source pour en comprendre le fonctionnement. Toute personne sensée conviendra qu'un tel projet n'est pas mature.

Pourtant, de nombreux outils existent pour faciliter cette tâche. Je vais vous présenter Sphinx, qui rend la documentation d'une API (et plus généralement de tout projet) une tâche aisée, grâce notamment à la découverte automatique des endpoints.

De par les intégrations disponibles, ce tutoriel s'adresse plus particulièrement aux développeurs utilisant Flask, Bottle ou Tornado.

Inclure la documentation dans les docstrings

Un des problèmes les plus souvent mentionnés à propos de la documentation est l'obsolesence. Les développeurs changent le code, mais pas la documentation qui va avec… L'approche que je vais proposer mitige ce problème par la proximité entre le code et sa documentation. Il est bien plus facile de penser à changer la documentation du code lorsqu'elle est sous nos yeux !

L'astuce est de placer la documentation dans la docstring de la fonction liée à un endpoint. Il suffit de l'écrire avec une syntaxe bien spécifique pour que tout se retrouve sur une belle documentation.

Pour ceux qui ne le savent pas, une docstring est une chaîne de caractère placée avant la première instruction d'une fonction. Elle est là pour informer le lecteur à propos de la fonction. En voici un exemple:

def foo():
    """Ceci est une docstring"""
    pass

Avec Sphinx, nous pouvons inclure dedans des informations sur:

  • Les Headers utilisés
  • Ce que renvoie l'endpoint
  • Le corps de requête attendu
  • Les paramètres présents dans l'URL
  • Les "query parameters" disponibles à l'utilisation
  • Les différents codes de retour susceptibles de servir de réponse

La syntaxe est la suivante:

:<emplacement> <nom>: <description>

L'emplacement est la source documentée, par exemple l'URL ou le corps de la réponse.

Le nom est celui utilisé par un paramètre ou un champ.

La description peut être variée mais contiendra généralement des détails d'utilisation sur ce qui est documenté.

Nous allons voir un cas plus pratique pour en avoir un aperçu:

def get_user(id):
    """Retourne les informations sur l'utilisateur référencé par un id

    :param id: L'identifiant de l'utilisateur demandé
    :query details: Si ce paramètre est présent, plus d'informations sont
    renvoyés à propos de l'utilisateur.
    :status 200: L'utilisateur a été trouvé et est renvoyé
    :status 404: Aucun utilisateur n'a été trouvé avec cet id
    """
    pass

Vous voyez que la syntaxe est tout aussi bien lisible par un humain que par une machine. Elle est donc utile à la fois pour le développeur de l'API et pour la génération d'une documentation.

Vous pouvez jetez un œil à la documentation de cette syntaxe pour plus de détails.

Installer et préparer Sphinx

Comme toute librairie Python, vous pouvez l'installer via pip:

pip install Sphinx

Pour commencer la documentation d'un projet, Sphinx dispose d'une commande qui met tout en place en fonction de quelques questions simples. Vous pouvez la lancer avec sphinx-quickstart.

Quand une valeur est entre crochets, il s'agit de la valeur par défaut, qui sera utilisée si vous n'entrez aucun texte.

La racine de la documentation (root path for documentation) est généralement "docs".

Je vous conseille de séparer le dossier source du dossier build, parce que la suite du tutoriel utilise ce modèle, mais vous pouvez faire autrement.

Vous pouvez remplir les autres champs en fonction de vos préfèrences ou en laissant les valeurs par défaut.

Obtenir la documentation automatique des endpoints d'une application

Charger l'extenstion

Pour générer automatiquement la documentation des endpoints, il va falloir commencer par activer l'extension qui nous le permet. Ça va dépendre du framework que vous utilisez. Il s'agira de l'une des suivantes:

  • sphinxcontrib.autohttp.flask
  • sphinxcontrib.autohttp.bottle
  • sphinxcontrib.autohttp.tornado

Vous devez donc l'ajouter dans la liste des extensions, présente dans le fichier docs/source/conf.py si vous utilisez les mêmes réglages que moi.

Accéder aux modules

La génération de la documentation sera faite depuis le dossier docs. Il est donc très probable que vous ayez à décommenter ces lignes au début du fichier conf.py:

import os
import sys

sys.path.insert(0, os.path.abspath('../..'))

Attention, le chemin inséré est différent de celui par défaut si comme moi, vous séparez les dossier source et build.

Insérer la documentation des endpoints dans le build

Il est temps d'ajouter dans les fichiers de documentation une directive permettant de documenter automatiquement votre API. Je vais le montrer d'une certaine façon mais vous voudrez sûrement le personnaliser par la suite.

Là encore, il faudra utiliser une directive différente en fonction du framework. Vous pouvez les trouvez ici. Je vais faire mon example avec Flask mais choisissez le vôtre parmi:

  • autoflask
  • autobottle
  • autotornado

Pour ma part, je vais la placer dans le fichier docs/source/endoints.rst que je vais ensuite linker dans l'index de la documentation.

docs/source/endpoints.rst:

Endpoints' documentation
########################

.. autoflask:: example.app:app
    :include-empty-docstring:

docs/source/index.rst:

Welcome to Example API's documentation!
=======================================

.. toctree::
   :maxdepth: 2
   :caption: Contents:

   endpoints

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

Dans cette example, l'application Flask serait dans un fichier example/app.py et l'objet s'appelerait app.

À ce point, vous devriez pouvoir générer la documentation et voir vos endpoints apparaître. Pour lancer la génération, la commande est la suivante (Attention, elle n'est disponible que si vous avez accepter d'avoir un Makefile pendant sphinx-quickstart):

make -C docs html

Vous pouvez ensuite l'ouvrir dans votre navigateur, par exemple firefox, avec:

firefox docs/build/html/index.html

Mettre la documentation à disposition

Il va maintenant falloir mettre cette documentation à disposition des utilisateurs, pour lui donner une utilité !

Cela pourrait faire l'objet d'un article en soi tellement les choix sont nombreux, mais certains sont plus accessibles que d'autres. Aucune ne sera détaillée ici mais voici quelques idées pour commencer simple:

  • Inclure des instructions pour compiler la documentation dans le fichier README.rst ou README.md.
  • Héberger la documentation sur github pages.
  • Héberger la documentation sur un CDN.