Pour faire suite aux articles de Théo sur la mise en place d’une API RESTful avec l’utilisation de la gem Grape, nous allons aujourd’hui nous intéresser à la génération de la documentation de l’API.
Pour rappel, voici les liens ainsi que les dépôts Github de ces articles :
La rédaction de la documentation d’une API est une chose assez redoutée par de nombreux développeurs. Il est fastidieux de lister à la main tous les endpoints disponibles ainsi que tous les paramètres possibles associés avec leur explication. C’est la raison pour laquelle certaines personnes prennent des raccourcis, ce qui est dommage car une documentation bien conçu est la clé de la réussite de votre API (aussi bien publique que privée).
Même lorsqu’on nous prenons le temps de rédiger une documentation digne de ce nom, il faut ensuite la maintenir car une API a tendance à évoluer très vite et il faut que sa documentation reste à jour.
Afin de palier à ce problème, j’ai donc recherché un moyen de la générer automatiquement à partir du code. En effet cette solution permettrait de développer notre API tout en générant automatiquement sa documentation et donc sa mise à jour.
En réalisant mes recherches, je suis tombé sur des services sympa mais payant comme apiary.io et des services open source comme Docco, Dexy ou Swagger. Mon choix s’est rapidement arrêté sur Swagger.
En effet, Swagger permet de décrire, produire, consommer et visualiser les services d’une API RESTful (Démo). De nombreuses références comme Apigee, Microsoft ou Paypal l’utilisent et il est 100% open source.
Ici nous allons utiliser la gem Grape mais il est tout à fait possible de faire sans, pour cela vous pouvez jeter un oeil à ce dépôt Github.
Swagger est développé en HTML et JavaScript et permet de créer une documentation interactive et très complète. Comme vous pouvez l’apercevoir sur le screenshot ci-dessus, il permet de catégoriser nos endpoints par ressource (pet, store ou user), puis utilise des codes couleurs pour spécifier le verbe HTTP utilisé sur l’endpoint. Au clic de l’un de ces endpoints vous avez le détail des paramètres attendus mais également le format de retour de l’API. Vous pouvez également consommer l’API depuis l’interface de documentation ce qui apporte une facilité de compréhension aux lecteurs.
Pour intégrer cette solution à notre projet Rails nous allons utiliser les gems suivantes :
Une fois notre Gemfile
complété, passons à la configuration de ces gems.
Créons un initializer qui contiendra la configuration de la gem grape-swagger-rails. Dans celui-ci nous allons renseigner le nom de notre documentation, l’url de notre application, ainsi que l’url souhaitée pour notre documentation.
GrapeSwaggerRails.options.url = '/api/swagger_doc'
GrapeSwaggerRails.options.app_name = 'CarWorldTrader'
GrapeSwaggerRails.options.app_url = 'http://localhost:3000'
Si vous utilisez différents environnements, je vous conseille de renseigner l’url de chacun dans votre fichier secrets.yml
, afin de pouvoir renseigner l’option app_url
de manière dynamique. Exemple :
GrapeSwaggerRails.options.app_url = Rails.application.secrets.app_domain_name
Il faut ensuite ajouter les routes répondant à votre documentation :
# config/routes.rb
mount GrapeSwaggerRails::Engine => '/apidoc'
A ce stade, l’interface de documentation de votre API est disponible à cette url http://localhost:3000/apidoc
mais vide.
Nous allons maintenant voir comment générer automatiquement notre documentation en modifiant légèrement notre code existant de l’API.
Commençons par mettre en place la configuration de la gem Grape_swagger
pour générer notre documentation. Cela se réalise via l’utilisation de la fonction add_swagger_documentation
.
# app/api/car_world_trader/base.rb
module CarWorldTrader
class Base < Grape::API
format :json
prefix :api
mount CarWorldTrader::V1::Cars
add_swagger_documentation(
base_path: "",
api_version: "1.0",
format: :json,
hide_documentation_path: true,
info: {
title: "CarWorldTrader API",
description: 'API to expose Cars informations form AutoTrader',
contact: "jfrancois@synbioz.com",
license: "All Rights Reserved"
}
)
end
end
base_path
: Chemin de base de l’API qui est exposée. Dans notre fichier routes.rb
nous avions mentionnés mount CarWorldTrader::Base => '/'
.api_version
: Version courante de l’APIformat
: Format de réponse de la documentation de l’APIhide_documentation_path
: Permet de cacher les routes permettant à swagger d’afficher la documentation.info
: Informations relatives à l’API qui seront affichées sur votre documentationD’autres options sont disponibles, je vous laisse consulter la documentation pour plus d’informations : Configuration.
A ce stade nous pouvons déjà voir la documentation générée. Nous allons utiliser la version 1.0 de l’API avec deux modifications :
Nous n’avons pas besoin d’authentification http_basic
pour nos tests, mais cela reste fonctionnel en l’utilisant. Il faudra juste renseigner les identifiants. Concernant ce point vous pouvez tout à fait mettre une authentification sur l’accès à la page de documentation de l’API. Pour cela, il suffit de le spécifier dans la configuration de la gem grape-swagger-rails
, retrouvez les indications ici.
L’interface de documentation nous permet déjà d’obtenir la liste de toutes nos routes disponibles sur notre API avec la possibilité de la tester.
L’interface répondant à la route /api/cars
en POST
:
Correspondant au code suivant :
desc "Create a car"
params do
requires :car, type: Hash do
requires :manufacturer, type: String, regexp: /^[A-Z][a-z]+$/
requires :design, type: String, values: ["tourer", "racing"]
requires :style, type: String
optional :doors, type: Integer, default: 3
end
end
post do
Car.create!(params[:car])
end
La description du code est donc utilisé par swagger pour documenter l’API.
Par défault la gem grape-swagger
va se servir des définitions des paramètres de votre route pour générer la documentation. Il prend en compte les paramètres requis ou non, le type, la valeur par défaut, les valeurs possibles etc… En résumé tout ce que permet de définir la gem Grape
sur les paramètres.
On peut donc générer la description ainsi que les informations sur les paramètres de notre endpoint. Afin de pouvoir documenter la réponse de l’appel API nous allons utiliser la gem grape-entity
.
Cette gem permet de choisir et de définir les attributs que votre endpoint API va exposer. Par ce biais, la gem grape-swagger
sera capable de l’inclure automatiquement dans notre documentation.
module CarWorldTrader
module V1
module Entities
class Car < Grape::Entity
expose :id, documentation: { type: 'integer', desc: 'Car ID' }
expose :manufacturer, documentation: { type: 'string', desc: 'Car manufacturer' }
expose :style, documentation: { type: 'string', desc: 'Car style' }
expose :doors, documentation: { type: 'integer', desc: 'Car number of doors' } }
end
end
class Cars < Grape::API
# version 'v1', using: :path
resource :cars do
...
desc "Create a car", entity: CarWorldTrader::V1::Entities::Car
params do
requires :car, type: Hash do
requires :manufacturer, type: String, regexp: /^[A-Z][a-z]+$/
requires :design, type: String, values: ["tourer", "racing"]
requires :style, type: String
optional :doors, type: Integer, default: 3
end
end
post do
present Car.create!(params[:car]), with: CarWorldTrader::V1::Entities::Car
end
...
end
end
end
end
Le module Entities
permet la création des différentes class
dont nous allons avoir besoin (ici nous n’avons qu’une seule ressource Car
). Nous spécifions ensuite les différents attributs que nous voulons exposer sur cette ressource via l’API. Retrouvez l’ensemble des paramètres possible pour la documentation sur le dépôt de la gem.
Ensuite nous allons intégrer cette documentation dans la description de notre route :
desc "Create a car", entity: CarWorldTrader::V1::Entities::Car
Ce qui va permettre de générer la mise à jour de l’interface de documentation en présentant le format et les attributs que va nous rendre l’appel API :
Il faut maintenant dire à notre API d’utiliser cette classe Entities
pour spécifier les attributs à exposer :
present Car.create!(params[:car]), with: CarWorldTrader::V1::Entities::Car
Dans notre cas, nous ne présentons pas les attributs created_at
et update_at
(juste pour l’exemple).
Avoir une interface de documentation qui s’adapte à notre code et se mettant à jour automatiquement est vraiment un gain de temps, d’autant que celle-ci permet de consommer l’API. Notre exemple est volontairement basique et nous n’avons pas parcouru l’ensemble des options possibles de la documentation mais le but de l’article est de vous mettre la puce à l’oreille sur ce genre d’outils.
En espérant que cela vous fasse gagner du temps et vous permette d’éditer des documentations API sans trop d’effort.
Les sources de cet article sont disponibles sur Github.
L’équipe Synbioz.
Libres d’être ensemble.