Microservices et contrats d'API : Jane comme source de vérité

JoliCode - JoliCodeBlog - 13/01
Dans le développement d'une API, nous sommes tous confrontés au même défi : maintenir la cohérence entre la documentation et le code. Qui n'a jamais perdu des heures à débugger une erreur parce que le champ user_id

Dans le développement d’une API, nous sommes tous confrontés au même défi : maintenir la cohérence entre la documentation et le code.

Qui n’a jamais perdu des heures à débugger une erreur parce que le champ user_id était devenu userId dans le code, mais pas dans la documentation ? C’est ce qu’on appelle le « drift ». À mesure que le projet évolue, le code change, mais la documentation (OpenAPI, Wiki, Postman) traîne souvent la patte, devenant une source d’erreurs plutôt qu’une aide.

Et si la solution n’était pas de mettre à jour manuellement notre code pour coller à la doc, mais de générer automatiquement notre code à partir de la doc ? C’est ici qu’intervient Jane.

Section intitulée decouvrir-janeDécouvrir Jane

En deux mots : Jane est une suite de librairies PHP dont la mission est de générer du code de qualité à partir de vos spécifications JSON Schema ou OpenAPI.

Si l’on devait résumer son rôle dans une API moderne, Jane agit comme le « traducteur automatique » entre vos contrats d’interface (vos spécifications .yaml ou .json) et votre code PHP. Au lieu d’écrire manuellement vos classes, vos validateurs et vos clients HTTP — une tâche répétitive et sujette à l’erreur humaine — Jane les fabrique pour vous.

Concrètement, Jane analyse votre schéma et produit :

  • Des Modèles (DTO) : Des classes PHP simples (POPO – Plain Old PHP Objects) strictement typées qui représentent vos données ;
  • Des Normalizers : Toute la logique nécessaire pour transformer ces objets en JSON et inversement, en s’appuyant sur le composant symfony/serializer ;
  • Un Client HTTP complet : (dans le cas du composant OpenAPI) Une implémentation prête à l’emploi (compatible PSR-18) pour consommer l’API, gérant les requêtes, les réponses et même les exceptions définies dans votre spec.

L’atout majeur de Jane n’est pas seulement le gain de temps, c’est la garantie de conformité. Puisque le code est généré directement depuis la source de vérité (le schéma), il est impossible d’avoir une divergence (« drift ») entre ce que votre documentation prétend faire et ce que votre code fait réellement. Si le schéma change, vous régénérez le code, et le tour est joué.

Section intitulée strong-voyons-un-projet-d-exemple-strongVoyons un projet d’exemple

Pour passer de la théorie à la pratique, nous allons construire un cas d’usage classique : un tunnel d’achat e-commerce.

Nous allons simuler la transformation d’un panier en une commande validée. Pour cela, nous découpons la logique en deux micro-services distincts :

  1. Le service Panier : Il matérialise l’état d’attente avant la commande. C’est lui qui mémorise les articles choisis au fur et à mesure que le client parcourt le site, avant qu’il ne décide (ou non) de passer à l’achat ;
  2. Le service Commande : Il gère la finalisation de la vente et la collecte des informations client.

Ce scénario nous permettra d’explorer des cas concrets :

  • Côté Panier, nous utiliserons des UUID pour récupérer le contenu du panier ;
  • Côté Commande, nous mettrons en place une validation stricte des données (regex pour le téléphone, énumération pour le pays) lors de la transformation du panier en commande, ainsi qu’un endpoint pour les codes promo.

Voyons maintenant comment formaliser tout cela dans nos contrats d’API.

Section intitulée strong-creer-nos-micro-services-1–2-panier-strongCréer nos micro-services (1 / 2) : Panier

Commençons par le service le plus simple : le Panier.

Ici, nous prenons le parti du Design First : avant d’écrire la moindre ligne de PHP, nous allons figer la structure de nos échanges dans un fichier cart.yaml.

Pour ce service, le besoin est basique : nous voulons pouvoir récupérer un panier via son identifiant unique. Voici notre définition en OpenAPI 3.0.3 :

openapi: 3.0.3 info: title: 'Service Panier' version: 1.0.0 paths: /carts/{id}: get: summary: 'Récupérer un panier' parameters: - name: id in: path required: true schema: type: string format: uuid responses: '200': description: 'Le panier trouvé' content: application/json: schema: $ref: '#/components/schemas/Cart' components: schemas: Cart: type: object properties: id: type: string format: uuid items: type: array items: type: string # simplifié pour l'exemple

Section intitulée strong-ce-qu-il-faut-retenir-ici-strongCe qu’il faut retenir ici

L’utilisation du format uuid sur l...
[Courte citation de 8% de l'article original]

Loading...