Accueil / Articles / Six styles API comparés : REST, GraphQL, WebSockets, Webhooks, gRPC, SOAP

Six styles API comparés : REST, GraphQL, WebSockets, Webhooks, gRPC, SOAP

Découvrez comment REST, GraphQL, WebSockets, webhooks, gRPC et SOAP résolvent chacun des problèmes différents liés à l’échange de données, ainsi qu’une carte de décision pour choisir le bon outil.

2251 mots

La plupart des gens adoptent REST comme premier style d’API, le considérant alors comme la solution universelle. Ce n’est pas le cas. REST n’est qu’une des six options possibles, et les cinq autres existent précisément parce que REST rencontre des limites réelles dans certaines situations : mises à jour en temps réel, appels rapides entre services internes, exigences strictes de sécurité au sein d’une entreprise, et structures de données flexibles. Chaque autre style d’API présenté ici a été conçu pour gérer des situations où REST peine.

Si REST vous est déjà familier, ce qui suit expliquera exactement quand vous devriez changer d’outil et pourquoi.

Qu’est-ce qu’une API (un paragraphe, puis nous continuons)

En son essence, une API se situe entre deux systèmes et leur permet de communiquer. Lorsque vous saisissez « biryani » dans une application de livraison de nourriture, les résultats ne se trouvent pas déjà sur votre téléphone. Votre application envoie une demande au serveur de l’entreprise, et le serveur répond avec des données correspondantes. Les règles qui régissent cet échange — la manière dont la demande est formulée, l’apparence de la réponse — constituent l’API. Imaginez un serveur dans un restaurant : vous n’allez jamais dans la cuisine pour prendre votre propre nourriture ; vous dites au serveur ce que vous souhaitez, et c’est lui qui s’occupe du reste. Ce serveur est essentiellement l’API.

Il s’avère qu’il existe six types distincts de « serveurs » que vous pourrez rencontrer.

REST : La norme, et ses limites

REST, abréviation de Representational State Transfer, fonctionne sur HTTP et repose sur deux idées fondamentales : une URL qui identifie la ressource souhaitée, et une méthode HTTP qui décrit l’action à effectuer sur elle.

Quatre méthodes couvrent presque tout : GET récupère des données, POST crée un nouveau enregistrement, PUT met à jour ou remplace un enregistrement existant, et DELETE le supprime. Une caractéristique clé de REST est son absence d’état — le serveur ne conserve aucune mémoire des interactions précédentes avec l’utilisateur. Tout contexte nécessaire doit être inclus dans la requête elle-même, à chaque fois.

GET https://api.zomato.com/v1/restaurants?search=biryani
Authorization: Bearer <token>

Lorsque cette requête arrive, le serveur vérifie l’identité de l’utilisateur, récupère les enregistrements pertinents dans la base de données, puis renvoie un chargement JSON.

Où il s’applique : les API destinées au grand public, les applications standard de création, lecture, mise à jour et suppression, ainsi que tout scénario où le client et le serveur sont clairement séparés et nécessitent un contrat prévisible et bien documenté. REST a obtenu ce statut par défaut pour une bonne raison : il est simple, ne nécessite pas que le serveur suive l’état de la session, est largement compris et fonctionne sur HTTP pur.

Où il manque de pertinence : tout ce qui nécessite des mises à jour en temps réel (applications de chat, suivi en direct de la localisation), les cas où une seule interface nécessite des données provenant de plusieurs ressources différentes en même temps, ou la communication entre services internes où la vitesse brute prime sur la lisibilité pour l’humain.

GraphQL : Demandez exactement ce dont vous avez besoin

REST présente un problème bien connu : le sur-récupération de données. Lorsque vous appelez une extrémité /user, vous pouvez obtenir le nom, la photo de profil, l’âge, le département, le salaire et une douzaine d’autres champs — alors que tout ce que vous vouliez vraiment, c’était le nom et la photo. L’aspect négatif correspondant est le sous-récupération de données, où une seule vue nécessite des éléments provenant de plusieurs ressources, vous obligeant à effectuer plusieurs appels REST avant de combiner les résultats côté client.

GraphQL résout ces deux problèmes en même temps : une seule extrémité, associée à un langage de requête qui permet au client de spécifier précisément quels champs il souhaite obtenir.

# Instead of hitting /employees/123 and getting everything,
# you describe precisely what you need in the request body
query {
  employee(id: "123") {
    name
    photo
  }
}

La réponse ne contient que ces deux champs demandés — rien de supplémentaire. Besoin du salaire également ? Il suffit de l’ajouter à la requête. Il n’est pas nécessaire de créer une extrémité séparée pour cela.

GraphQL prend en charge trois types d’opérations. Une query lit des données, jouant le même rôle qu’une requête GET REST. Une mutation écrit ou modifie des données, équivalant à une combinaison de POST, PUT et DELETE. Une subscription ouvre un flux de données en temps réel pour des mises à jour continues, fonctionnant de manière très similaire aux WebSockets.

Où il s’applique : des interfaces utilisateur riches en fonctionnalités nécessitant des structures de données flexibles, des applications mobiles où il est important de réduire la taille du chargement, ainsi que dans toute situation où plusieurs types de clients — web, mobiles, intégrations tierces — accèdent au même backend mais ont chacun besoin d’un fragment de données différent.

Ses limites : des services CRUD de base pour lesquels les endpoints simples de REST suffisent amplement. GraphQL introduit une véritable complexité du côté serveur, le cache devient nettement plus difficile à gérer qu’avec REST, et représente souvent un surcoût inutile lorsque les besoins en données sont stables et bien définis.

WebSockets : La connexion persistante

Les fonctionnalités en temps réel révèlent une faiblesse fondamentale de REST. Pour savoir s’un nouveau message de chat est arrivé, un client basé sur REST devrait continuer à effectuer des requêtes répétées : « Y a-t-il du nouveau ? » encore et encore. Multipliez cela par un million d’utilisateurs simultanés, et vous obtenez un million de requêtes par seconde, la grande majorité répondant « non », ce qui représente un pur gaspillage de ressources.

WebSockets évitent complètement ce problème en remplaçant le modèle demande-réponse par une connexion persistante et bidirectionnelle. Elle commence comme une requête HTTP ordinaire, mais qui contient en tête un en-tête d’amélioration spécial :

GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade

Lorsque le serveur accepte, cette connexion HTTP se transforme en une connexion WebSocket. Dès lors, chacune des parties peut envoyer un message à l’autre à tout moment, sans avoir besoin de demander d’abord la permission. Le canal reste ouvert jusqu’à ce que l’une des parties le ferme délibérément.

Connecting (la mise en relation est en cours), Open (les messages circulent dans les deux sens), Closing (la fermeture a commencé) et Closed (la connexion n’existe plus). Tenter d’envoyer des données via une connexion déjà fermée fera planter le serveur — c’est une erreur fréquente chez les débutants.

Où cela est utilisé : chat en direct, jeux multijoueurs, outils d’édition collaborative en temps réel tels que les documents partagés, les scores sportifs en direct et les notifications push — en somme, dans tout cas où le serveur doit envoyer des données sans sollicitation.

Ses limites : la récupération de données ordinaire, où le client n’a besoin d’informations que lorsqu’il les demande explicitement. Comme les WebSockets maintiennent des connexions ouvertes en permanence, ils consomment des ressources serveur. Les déployer là où un simple REST suffirait représente une perte inutile de capacité.

Webhooks : Le serveur vous appelle

REST et WebSockets partent tous deux du client : c’est le client qui ouvre la connexion, envoie la demande et reçoit une réponse du serveur. Les Webhooks inversent complètement ce flux — au lieu que vous demandiez des mises à jour au serveur, c’est le serveur qui vous contacte dès qu’un événement important se produit.

La mécanique est simple. Vous enregistrez une URL auprès d’un service tiers et indiquez ce qu’il doit faire avec cette URL : par exemple, « lorsqu’un paiement est terminé, envoyez une requête POST ici ». Dès que le paiement est effectivement confirmé, le fournisseur de paiement — Razorpay, Stripe ou celui que vous utilisez — envoie automatiquement une requête vers votre point d’arrivée. Il n’y a pas de boucle de surveillance, ni besoin de maintenir une connexion en permanence. Il vous suffit d’attendre que l’appel arrive.

# What you give Razorpay in setup:
Webhook URL: https://yourapp.com/webhooks/payment
# What Razorpay sends when payment completes:
POST https://yourapp.com/webhooks/payment
{
  "event": "payment.captured",
  "payload": { "amount": 50000, "order_id": "order_abc" },
  "signature": "sha256_hash_here"
}

La vérification de la signature n’est pas optionnelle ici — c’est tout le système de sécurité. Votre point d’entrée webhook est accessible publiquement, ce qui signifie que n’importe qui pourrait, en théorie, envoyer un événement falsifié « payment.captured » pour faire croire à votre système qu’une commande a été payée alors qu’en réalité elle ne l’a pas été. La signature incluse dans la charge utile est un hash cryptographique qui prouve que la demande provient bien du fournisseur. Votre serveur doit vérifier cette signature avant d’agir sur quoi que ce soit dans le corps de la demande.

Quand l’utiliser : pour les confirmations de paiement, les changements d’état des commandes, les pipelines CI/CD (GitHub qui notifie votre serveur dès qu’un nouveau code est déposé), et en général dans tout workflow où vous réagissez à un événement survenu dans un système externe.

Quand ne pas l’utiliser : pour tout ce qui nécessite une réponse immédiate au cours de la même interaction avec l’utilisateur. Les webhooks fonctionnent a posteriori — ils sont intrinsèquement asynchrones. Lorsqu’un utilisateur est en train d’attendre une confirmation devant son écran, REST reste la meilleure solution.

gRPC : Vitesse binaire pour les services internes

Une application importante n’est rarement constituée d’un seul serveur. Une plateforme comme Zomato, par exemple, met en œuvre des services distincts pour les commandes, les paiements, les notifications et les données des restaurants, et ces services s’appellent mutuellement des milliers de fois par seconde. Si toute cette communication interne passe par REST, il faut constamment sérialiser et désérialiser du JSON. La lisibilité du JSON est excellente pour un développeur qui consulte des journaux, mais cette même lisibilité entraîne un coût de parsing réel lorsque le volume est élevé.

gRPC, initialement développé par Google pour gérer son propre trafic interne, remplace JSON par Protocol Buffers (Protobuf) — un format binaire bien plus compact et qui se code et se décode beaucoup plus rapidement. Le même chargement de données que REST enverrait sous forme de texte lisible est transmis par gRPC sous forme d’un bloc binaire dense que les machines peuvent traiter bien plus vite.

// You define your data structure once in a .proto file
message OrderRequest {
  string order_id = 1;
  string user_id = 2;
  float amount = 3;
}

L’amélioration des performances ne dépend pas uniquement du format des données. gRPC fonctionne également sur HTTP/2, ce qui permet le multiplexage — des milliers de requêtes peuvent être transmises simultanément via une seule connexion partagée, contrairement à HTTP/1.1 qui les traite une par une. De plus, gRPC propose quatre modèles de communication distincts : Unary (une seule requête associée à une seule réponse, avec la même structure que REST), Server Streaming (une requête qui déclenche un flux de réponses, utile pour le suivi en temps réel des commandes), Client Streaming (de nombreuses requêtes regroupées en une seule réponse finale, pratique pour télécharger un fichier par tranches), et Bidirectional Streaming (les deux parties échangent continuellement des données, ce qui convient aux fonctionnalités collaboratives en temps réel).

Quand l’utiliser : pour le trafic service-à-service au sein de votre propre infrastructure, où la vitesse et le typage strict sont essentiels. Partout où vos services échangent de grands volumes de requêtes et où l’analyse JSON représente un coût mesurable.

Quand ne pas l’utiliser : pour les API destinées au grand public, consommées par des navigateurs ou des développeurs externes. La nature binaire de Protobuf rend son inspection et sa débogage beaucoup plus difficiles, et son fonctionnement dans un navigateur nécessite des préparatifs supplémentaires. Pour tout produit destiné aux utilisateurs finaux, REST reste le choix le plus pratique.

SOAP : strict, verbeux, mais toujours utilisé par les banques

SOAP (Simple Object Access Protocol) date de 1998, ce qui en fait un standard plus ancien que REST lui-même. Aujourd’hui, la plupart des développeurs ne le rencontrent que lorsqu’ils se connectent à des systèmes bancaires, des plateformes d’assurance ou à de gros logiciels d’entreprise — des secteurs qui ont adopté SOAP tôt et n’ont jamais eu de raison valable de s’en éloigner.

SOAP ne fait pas de compromis. Chaque message est un XML emballé à l’intérieur d’une enveloppe strictement définie. Alors que REST laisse beaucoup de liberté quant à la manière de structurer les données, SOAP exige que toutes les parties respectent un schéma précis et prédéfini.

<!-- Every SOAP message follows this envelope structure -->
<Envelope>
  <Header>
    <Security><!-- authentication goes here --></Security>
  </Header>
  <Body>
    <GetAccountBalance>
      <AccountId>ACC123</AccountId>
    </GetAccountBalance>
  </Body>
</Envelope>

Cette structure lourde existe délibérément. La norme WS-Security de SOAP regroupe l’authentification, les signatures numériques et le chiffrement dans un seul message. Pour les transactions financières, où toute altération pendant le transfert pourrait causer des dommages réels, cette couche de protection intégrée justifie son encombrement supplémentaire.

Quand l’utiliser : pour se connecter à une API bancaire, à un passerelle de paiement exigeant SOAP, à des systèmes gouvernementaux, à des plateformes d’assurance, ou à tout système d’entreprise ancien ne proposant qu’une interface SOAP. Il est peu probable que vous choisissiez SOAP pour un projet créé de zéro, mais en comprendre les principes est essentiel lorsque vous devez interagir avec des systèmes basés sur cette technologie.

Quand ne pas l’utiliser : pour tout nouveau projet où vous contrôlez les deux parties de la communication. SOAP nécessite plus de temps pour être mis en œuvre, ses en-têtes XML rendent le débogage fastidieux, et il n’apporte aucun avantage par rapport à REST ou gRPC lorsque la compatibilité avec des systèmes anciens n’est plus une contrainte.

Le schéma de décision

Utilisez ceci comme référence rapide pour choisir l’outil approprié :

Ce que vous comprenez maintenant

REST reste le choix par défaut. Chaque autre modèle existe pour combler une lacune spécifique où REST échoue : GraphQL intervient lorsque les besoins en données varient d’un client à l’autre, WebSockets lorsqu’une connexion doit rester ouverte dans les deux sens, Webhooks lorsque l’on veut réagir aux événements plutôt que de les demander constamment, gRPC lorsque JSON devient trop lent pour le trafic entre services internes, et SOAP lorsque des exigences de sécurité de niveau entreprise ne laissent aucune autre option.

Lors de la conception d’une intégration, ne commencez pas par vous demander comment forcer l’utilisation de REST. Demandez plutôt quel modèle de communication correspond réellement aux besoins du système. C’est cette réponse qui doit déterminer l’outil à utiliser, et non une habitude.

En tant que prochaine étape, choisissez l’un de ces modèles avec lesquels vous n’avez pas encore travaillé. Trouvez sa documentation officielle ou un petit projet open source basé sur lui, et lisez une implémentation réelle avant d’être contraint de en créer une sous pression.