APIs et contrats

Conception d'APIs, comparaison entre REST, GraphQL et gRPC, versionnage des APIs et l'approche contract-first.

Communication entre composants

Dans une architecture moderne, les composants n’ont pas seulement besoin d’exister ; ils doivent communiquer de manière claire, stable et compréhensible. C’est là qu’interviennent les APIs et les contrats.

Les décisions relatives aux APIs affectent directement la maintenabilité, l’évolutivité et l’expérience de développement de l’ensemble du système.

Qu’est-ce qu’une API ?

Une API est une interface qui permet à un système ou à un composant d’exposer des capacités à d’autres.

En termes simples, une API définit :

  • Ce que vous pouvez demander
  • Comment vous devez le demander
  • Quelle réponse vous pouvez attendre
  • Quelles erreurs peuvent survenir

Dans tout système distribué, les APIs constituent le mécanisme de communication entre les composants. Une API bien conçue agit comme un contrat : elle définit ce qu’un consommateur peut demander, ce qu’il va recevoir et sous quelles conditions.

REST (Representational State Transfer)

REST est le style architectural le plus utilisé pour les APIs web. Il repose sur des ressources identifiées par des URLs et sur des opérations HTTP standard.

Principes fondamentaux

  • Ressources : Tout est une ressource identifiée par une URI (/usuarios/123).
  • Verbes HTTP : GET (lire), POST (créer), PUT (remplacer), PATCH (mettre à jour partiellement), DELETE (supprimer).
  • Sans état : Chaque requête contient toutes les informations nécessaires ; le serveur ne conserve aucun état de session.
  • Représentations : Une ressource peut avoir plusieurs représentations (JSON, XML).

Exemple d’API REST

GET    /api/pedidos          → Lista de pedidos
GET    /api/pedidos/42       → Detalle del pedido 42
POST   /api/pedidos          → Crear nuevo pedido
PATCH  /api/pedidos/42       → Actualizar pedido 42
DELETE /api/pedidos/42       → Eliminar pedido 42

Quand est-ce utile

  • APIs simples ou de taille moyenne
  • Intégration entre services
  • Interfaces publiques ou privées bien définies
  • Lorsque vous avez besoin de la mise en cache HTTP native

Avantages de REST

  • Largement adopté et compris par l’industrie.
  • Cacheable nativement grâce aux headers HTTP.
  • Outils matures pour la documentation (OpenAPI/Swagger).
  • Fonctionne bien avec l’infrastructure web existante (proxies, CDNs, load balancers).

Inconvénients de REST

  • Over-fetching : Le endpoint renvoie plus de données que celles dont le client a besoin.
  • Under-fetching : Le client doit effectuer plusieurs requêtes pour obtenir des données liées.
  • Pas de typage natif ; dépend d’une documentation externe pour définir la structure.

GraphQL

GraphQL est un langage de requête pour APIs qui permet au client de spécifier exactement les données dont il a besoin.

Comment ça fonctionne

# El cliente pide exactamente lo que necesita
query {
  pedido(id: 42) {
    id
    fecha
    total
    cliente {
      nombre
      email
    }
    items {
      producto
      cantidad
    }
  }
}

Avantages de GraphQL

  • Ni over-fetching ni under-fetching : Le client définit la forme de la réponse.
  • Un seul endpoint : Toutes les requêtes passent par /graphql.
  • Typage fort : Le schema définit explicitement les types, les champs et les relations.
  • Introspection : Le client peut découvrir le schema disponible à l’exécution.
  • Très adapté aux BFFs pour l’agrégation de données.

Coûts de GraphQL

  • Complexité côté serveur : La résolution de requêtes imbriquées peut engendrer des problèmes de performance (requêtes N+1).
  • Mise en cache difficile : Comme il n’utilise pas d’URLs uniques par ressource, la mise en cache HTTP standard ne s’applique pas directement.
  • Courbe d’apprentissage : Nécessite de comprendre un nouveau paradigme, tant côté client que côté serveur.
  • Sécurité : Des requêtes complexes peuvent être exploitées pour des attaques par déni de service si elles ne sont pas limitées.
  • Un contrôle plus délicat de la performance et une observabilité un peu différente de REST.

gRPC

gRPC est un framework de communication haute performance qui utilise Protocol Buffers (protobuf) pour la sérialisation et HTTP/2 comme transport.

Définition du service

syntax = "proto3";

service ServicioPedidos {
  rpc ObtenerPedido (PedidoRequest) returns (PedidoResponse);
  rpc CrearPedido (CrearPedidoRequest) returns (PedidoResponse);
  rpc ListarPedidos (ListarRequest) returns (stream PedidoResponse);
}

message PedidoRequest {
  int32 id = 1;
}

message PedidoResponse {
  int32 id = 1;
  string fecha = 2;
  double total = 3;
}

Avantages de gRPC

  • Haute performance : La sérialisation binaire (protobuf) est plus rapide et plus compacte que JSON.
  • Streaming bidirectionnel : Prend en charge la communication en temps réel avec HTTP/2.
  • Génération de code : À partir du fichier .proto, on génère des clients et des serveurs dans plusieurs langages.
  • Contrats stricts : Le schema protobuf est le contrat ; il n’y a aucune ambiguïté.

Inconvénients de gRPC

  • Ne fonctionne pas directement dans les navigateurs (nécessite gRPC-Web comme proxy).
  • Débogage difficile : Les messages binaires ne sont pas lisibles sans outils spécialisés.
  • Adoption plus faible : Moins d’outils et de documentation par rapport à REST.
  • Complexité de mise en place : Nécessite un compilateur protobuf et une configuration supplémentaire.

Comparaison directe

CritèreRESTGraphQLgRPC
Format de donnéesJSON (texte)JSON (texte)Protobuf (binaire)
TransportHTTP/1.1 ou HTTP/2HTTP/1.1 ou HTTP/2HTTP/2
TypageExterne (OpenAPI)Natif (schema)Natif (protobuf)
Cas d’usage idéalAPIs publiques, CRUDFrontends avec données complexesCommunication entre services
PerformanceBonneVariableExcellente
CacheHTTP natifNécessite une solution customNon standard
Courbe d’apprentissageFaibleMoyenneMoyenne-Élevée

Qu’est-ce qu’un contrat

Un contrat est l’accord entre le producteur et le consommateur. Il peut définir :

  • La structure de la requête et de la réponse
  • Les champs obligatoires et optionnels
  • Les types de données
  • Les erreurs possibles
  • Les headers requis
  • Les règles de versionnage

Un contrat réduit l’ambiguïté et aide à faire évoluer les systèmes sans casser les consommateurs.

Contrats dans les événements

Les APIs ne sont pas les seules à avoir des contrats. Les événements ont eux aussi besoin de schémas clairs.

Par exemple, si un service publie OrderPlaced, les autres services doivent savoir :

  • Quels champs il contient
  • Ce qu’ils signifient
  • Lesquels sont obligatoires
  • Comment le schema évolue

Outils de contrat par technologie

TechnologieOutil de contrat
RESTOpenAPI (Swagger)
GraphQLSDL (Schema Definition Language)
gRPCProtocol Buffers (.proto)
ÉvénementsAsyncAPI

Conception Contract-First

L’approche contract-first (contrat d’abord) propose de définir l’API avant de l’implémenter. Au lieu d’écrire du code puis de générer la documentation ensuite, vous définissez le contrat puis vous implémentez en vous appuyant dessus.

Flux contract-first

1. Definir el contrato (OpenAPI, protobuf, GraphQL schema)

2. Revisar y validar con consumidores

3. Generar código base (servidor y cliente)

4. Implementar la lógica de negocio

5. Validar que la implementación cumple el contrato

Avantages du contract-first

  • Développement en parallèle : Le frontend et le backend peuvent travailler simultanément en utilisant le contrat comme référence.
  • Documentation toujours à jour : Le contrat est la documentation.
  • Validation automatique : Des outils peuvent vérifier que l’implémentation respecte le contrat.
  • Meilleure communication : Le contrat est un artefact partagé entre les équipes.

Évolution et versionnage

Les contrats évoluent avec le temps. C’est pourquoi il est important de réfléchir à :

  • Compatibilité ascendante : Les changements ne doivent pas casser les consommateurs existants.
  • Dépréciation progressive : Marquez les endpoints ou les champs comme deprecated et laissez du temps pour migrer.
  • Changements breaking : Identifiez quand un changement est incompatible et nécessite une nouvelle version.
  • Ownership du contrat : Définissez qui est responsable de maintenir et de faire évoluer chaque contrat.

Stratégies courantes de versionnage

Versionnage par URL

GET /api/v1/pedidos
GET /api/v2/pedidos

C’est la stratégie la plus simple et la plus explicite. Le consommateur sait exactement quelle version il utilise.

Versionnage par header

GET /api/pedidos
Accept: application/vnd.miapi.v2+json

Garde les URLs propres mais est moins visible et plus difficile à tester dans le navigateur.

Versionnage par query parameter

GET /api/pedidos?version=2

Simple mais peut interférer avec le cache et n’est pas considéré comme une bonne pratique par de nombreuses équipes.

Bonnes pratiques de versionnage

  • Évitez les changements cassants : Ajoutez de nouveaux champs au lieu de modifier ceux qui existent déjà.
  • Dépréciez avant de supprimer : Marquez les endpoints comme deprecated et laissez aux consommateurs le temps de migrer.
  • Documentez les changements : Tenez un changelog clair entre les versions.
  • Limitez les versions actives : Ne maintenez pas plus de 2-3 versions simultanément.

Pourquoi les contrats sont importants

Sans contrats clairs :

  • Les équipes interprètent les choses différemment
  • Des intégrations fragiles apparaissent
  • Les changements cassent les consommateurs
  • Le couplage accidentel augmente

Avec des contrats bien définis :

  • Il y a moins d’ambiguïté
  • L’évolution devient plus sûre
  • Les équipes peuvent mieux se coordonner

Principes d’une bonne conception d’APIs

Quelle que soit la technologie choisie, ces pratiques s’appliquent à toute API :

  • Cohérence : Utilisez des conventions uniformes pour les noms, les formats et les codes d’erreur.
  • Idempotence : Les opérations GET, PUT et DELETE doivent produire le même résultat si elles sont exécutées plusieurs fois.
  • Gestion claire des erreurs : Renvoyez des codes de statut appropriés et des messages d’erreur utiles.
  • Pagination : Ne renvoyez jamais de collections complètes sans limite ; implémentez la pagination dès le départ.
  • Sécurité : Authentification (qui vous êtes) et autorisation (ce que vous pouvez faire) sur chaque endpoint.

Laquelle choisir ?

  • REST si vous avez besoin d’une API publique, simple et largement compatible.
  • GraphQL si votre frontend a besoin de flexibilité pour interroger des données complexes et liées.
  • gRPC si vous avez besoin d’une communication haute performance entre services internes.

Dans de nombreux systèmes réels, les trois technologies coexistent : REST pour les APIs publiques, GraphQL pour le BFF qui alimente le frontend, et gRPC pour la communication interne entre microservices.

Résumé

Les APIs permettent la communication entre composants. Les contrats rendent cette communication explicite, maintenable et évolutive. Dans les systèmes distribués, bien concevoir les contrats est tout aussi important que d’écrire le code qui les implémente.