1 points par GN⁺ 2025-01-24 | 1 commentaires | Partager sur WhatsApp
  • Le point de départ de la conception d’API est la différence entre RPC et REST ; les trois approches peuvent toutes s’appuyer sur HTTP, mais diffèrent par le modèle de création des appels et de construction des clients
  • REST repose sur un modèle hypertexte dans lequel on suit les URL fournies par le serveur, ce qui le distingue des API de type OpenAPI où le client compose le format des URL
  • OpenAPI définit les opérations via des modèles de chemins d’URL et des méthodes HTTP ; c’est pratique et largement utilisé, mais plus proche d’un modèle RPC mappé sur HTTP que de REST
  • gRPC définit directement une API RPC via un IDL, la génération de code, des charges utiles binaires et la gestion des connexions HTTP/2, en masquant les détails HTTP
  • gRPC nécessite un logiciel spécifique des deux côtés et présente des limites pour l’enrichissement par proxy, la prévention des mises à jour concurrentes et les mises à jour partielles ; il est donc particulièrement adapté aux API internes ou lorsqu’on peut utiliser une couche de conversion comme Cloud Endpoints

Trois modèles pour envisager les API basées sur HTTP

  • Les principales approches utilisant HTTP comme couche de transport d’API se divisent en REST, OpenAPI et gRPC
  • L’une des raisons pour lesquelles de nombreuses API publiques et API distribuées privées utilisent HTTP est que les organisations sont habituées aux enjeux de sécurité du trafic HTTP sur les ports 80 et 443
  • Les trois approches peuvent toutes être liées à HTTP, mais elles diffèrent sur ce qui sert d’adresse et sur la manière dont le client construit les appels

REST : suivre les URL sans les composer

  • En REST, le client utilise telles quelles les URL fournies par le serveur, sans considérer ni recomposer leur format comme une partie de la spécification de l’API
  • Un navigateur suit la page actuelle, les favoris ou l’URL saisie par l’utilisateur, et se contente d’extraire les informations de requête HTTP depuis l’URL ou de convertir une URL relative en URL absolue
  • Le cœur d’une API REST est l’usage de l’hypertexte / hypermédia, qui exprime les références entre ressources par les URL d’autres ressources
  • Avec l’approche REST, tous les identifiants sont échangés sous forme d’URL
    • POST /accountsaccount_URL
    • transmettre account_URL à POST /subscriptionssubscription_URL
    • GET {account_URL} → renvoie l’arborescence de données du compte
  • L’avantage de REST est sa proximité avec la stabilité, la cohérence et l’universalité du Web lui-même, et le modèle orienté entités de HTTP/REST peut rendre une API plus simple et plus régulière

OpenAPI : proche d’un RPC mappé directement sur HTTP

  • OpenAPI définit des modèles de chemins d’URL sous paths et appelle opération (operation) la combinaison d’un chemin et d’une méthode HTTP
  • Un chemin comme /pets/{petId} impose que le client connaisse la valeur de {petId} et l’insère dans le modèle d’URL pour construire une requête HTTP
  • Dans cette approche, le client doit connaître en détail le format des URL, ce qui va à l’encontre du modèle hypertexte de REST
  • Les raisons de l’adoption massive d’OpenAPI sont claires
    • son fonctionnement ressemble au modèle RPC traditionnel, familier pour les programmeurs
    • les concepts RPC peuvent être directement mappés sur des requêtes HTTP
  • Pour les API publiques, son grand avantage est d’être accessible depuis presque tous les langages et environnements avec les seules technologies HTTP standard
  • En contrepartie, il faut concevoir les chemins d’URL, les méthodes HTTP et le mapping des paramètres, ce qui augmente le nombre de détails à maîtriser tant pour le fournisseur que pour le consommateur de l’API

gRPC : une technologie RPC qui masque HTTP/2

  • gRPC utilise HTTP/2 comme couche de transport, mais n’expose pas les détails HTTP ni au concepteur de l’API ni au code client et serveur
  • Le flux d’appel d’un client gRPC est simple
    • déterminer la procédure à appeler
    • calculer les valeurs des paramètres à utiliser
    • transmettre ces paramètres au stub généré pour effectuer l’appel
  • gRPC définit les procédures distantes à partir d’un interface description language, sans avoir à exprimer comme avec OpenAPI le mapping entre chemins d’URL, paramètres et méthodes HTTP
  • Grâce à la génération de code, aux frameworks et aux bibliothèques, il peut être plus facile de produire des bibliothèques clientes et des implémentations serveur
  • L’usage de charges utiles binaires et de la gestion des connexions HTTP/2 apporte des avantages de performance ; on pourrait exploiter les mêmes techniques sans gRPC, mais cela demanderait davantage de compétences techniques

Quand envisager gRPC à la place d’OpenAPI

  • Lorsqu’on conçoit une API avec OpenAPI, il faut exprimer opérations et paramètres à travers des combinaisons de chemins d’URL et de méthodes HTTP, ce qui peut être délicat en raison du grand nombre de choix possibles
  • Si l’on conserve un modèle de type RPC, gRPC réduit la charge liée à la conception directe d’un mapping personnalisé vers HTTP
  • gRPC et OpenAPI ont un modèle d’API de base similaire, mais diffèrent dans leur manière d’exposer HTTP
    • OpenAPI expose au client les détails du transport HTTP, et le concepteur contrôle le mapping
    • gRPC masque les détails HTTP grâce à un mapping prédéfini et à du code généré
  • Le grand avantage d’OpenAPI reste que le client peut utiliser directement les outils et technologies HTTP standard, et pour de nombreux concepteurs d’API cet avantage justifie le coût de conception supplémentaire

Combiner un modèle orienté entités avec RPC

  • Même en utilisant gRPC ou OpenAPI, on peut retrouver certains avantages de REST en limitant les méthodes RPC à une organisation centrée sur les entités
  • L’idée consiste à commencer non pas par la définition des procédures, mais par celle des types de ressources, puis à associer à chaque type les opérations entité standard
  • Les opérations de base sont Create, Retrieve, Update, Delete et List, souvent résumées en CRUD plus List
  • On peut ajouter des opérations supplémentaires si nécessaire, mais mélanger concepts orientés entités et concepts orientés procédures peut faire perdre une partie des bénéfices
  • Le fait de regrouper les procédures par type d’entité est d’ailleurs l’une des idées centrales des langages orientés objet

Contraintes et points d’attention de gRPC

  • gRPC nécessite un logiciel spécifique côté client comme côté serveur, et le code généré doit être intégré au processus de build des deux côtés
  • Pour les utilisateurs de langages dynamiques comme JavaScript ou Python, où il peut y avoir très peu de processus de build dans l’environnement de développement, cette exigence peut être contraignante
  • Google Cloud Endpoints permet d’accéder à une API gRPC via HTTP et JSON, restaurant ainsi des options côté client, mais tous les utilisateurs ne peuvent pas s’en servir ni construire un équivalent
  • Avec une API REST, il est facile de créer un bot qui explore l’ensemble sans métadonnées ; à l’inverse, une API de type RPC comme gRPC ou OpenAPI nécessite des API et des métadonnées différentes selon les types d’entités, ou un logiciel sur mesure
  • Les API HTTP sont souvent enrichies via des outils de gestion d’API et des proxies comme Apigee Edge pour ajouter des fonctions de sécurité, de validation des entrées, de mapping de formats de données, ou de modification des en-têtes et du corps ; avec gRPC, ce type d’enrichissement par proxy peut être bien plus difficile
  • gRPC ne définit pas de mécanisme standard pour empêcher les pertes de données liées aux mises à jour concurrentes
    • HTTP fournit pour cela les en-têtes Etag et If-Match
  • gRPC ne définit pas non plus de mécanisme de mise à jour partielle
    • HTTP propose PATCH, ainsi que les standards JSON JSON merge patch et JSON patch
    • JSON merge patch est plus simple, mais ne couvre pas tous les cas, notamment les mises à jour de tableaux
    • JSON patch couvre davantage de cas, mais son utilisation est plus complexe

Critères de choix

  • Si vous savez déjà concevoir avec le modèle hypertexte REST, ou êtes prêt à l’apprendre, cela peut être un bon choix pour viser stabilité, cohérence et universalité
  • OpenAPI permet de créer des API accessibles avec les seules technologies HTTP standard, mais multiplie les choix de conception pour mapper les concepts RPC sur HTTP, ce qui peut compliquer la conception, l’implémentation et l’apprentissage
  • Si une API envisagée relève d’OpenAPI, gRPC mérite aussi d’être évalué. Les modèles d’API de base des deux approches sont comparables, et gRPC réduit le besoin de construire soi-même le mapping HTTP
  • gRPC est particulièrement attractif dans les cas suivants
    • lorsqu’un produit comme Cloud Endpoints permet aux clients de ne pas avoir à adopter obligatoirement la technologie gRPC
    • lorsqu’il s’agit d’une API interne, où l’on peut contrôler les choix technologiques du serveur et de tous les clients
  • Lorsqu’on adopte gRPC à la place d’OpenAPI ou de REST, il faut garder à l’esprit que les possibilités d’enrichir ou de corriger le comportement de l’API via des proxies fondés sur des outils de gestion d’API comme Apigee Edge peuvent être beaucoup plus limitées

1 commentaires

 
GN⁺ 2025-01-24
Avis sur Hacker News
  • Si je pouvais remonter le temps, j’aimerais empêcher qu’on me fasse apprendre gRPC dès le départ
    Au début, j’avais été séduit par la vision, mais quelques années plus tard, je me suis rendu compte que cela apportait bien trop de casse-tête. L’idée que cela masque les détails internes ressemble presque à une blague : on finit par déverser des logs de debug pour trouver pourquoi une requête échoue une fois sur dix, tout en ajustant 10 à 20 paramètres de timeout/retry aux noms ambigus
    Les plugins Maven, les étranges deadline exceeded, les load balancers qui n’aiment pas HTTP/2, les situations où il faut finalement utiliser une API standard à cause des pare-feu, la documentation médiocre, et même le fait d’obtenir des messages d’erreur exploitables pour l’observabilité : tout cela fait perdre du temps

    • Le problème de gRPC tient moins au protocole ou à protobuf lui-même qu’à la médiocrité, au moins, de la chaîne d’outils côté Java
      L’expérience développeur du code généré est mauvaise, les stubs client sont des classes concrètes final, donc difficiles à mocker dans les tests, et l’implémentation serveur doit elle aussi hériter d’une classe concrète plutôt que d’implémenter une interface
      Les méthodes serveur ont des signatures asynchrones, ce qui casse les comportements basés sur l’AOP comme @Transactional, il n’y a pas non plus de prise en charge des exceptions, et même si les classes de valeurs immuables sont appréciables, il faut toutes les construire via des builders
      Au final, pour utiliser gRPC dans une SOA, il faut écrire beaucoup de code de plomberie afin de masquer le bruit de gRPC et d’obtenir un code propre et testable ; le compilateur RPC de Thrift présente des problèmes similaires, avec d’autres soucis en plus
    • Ces problèmes semblent davantage relever d’implémentations particulières que de la spécification gRPC/protobuf elle-même
      Avec .NET et C# récents, l’expérience gRPC est plutôt bonne, au point que Microsoft a abandonné ses technologies RPC existantes comme WCF pour se concentrer sur gRPC
    • Le plus gros projet sur lequel je l’ai utilisé était en Java, et vérifier la sortie des bindings générés par protoc était plus verbeux et plus propice aux erreurs que de faire la sérialisation soi-même
      Le protocole sur le fil n’est pas type-safe ; il y a bien des tags de type, mais le même tag est réutilisé pour plusieurs types de données. L’encodage d’entiers zig-zag est également lent
      Comme bibliothèque RPC, c’est lamentable, et la seule chose pire que j’aie utilisée personnellement, c’était FlatBuffers
    • Vu que Maven est mentionné, il semble s’agir de Java ; pour ma part, après environ huit ans à programmer en Go, mon expérience avec gRPC est assez différente
      Je me demande si cette différence vient de Java ou de la technologie gRPC elle-même
    • J’utilise gRPC depuis plusieurs années avec une stack Go+Dart, et je n’ai jamais rencontré ce genre de problèmes
      Je me demande si ce sont des problèmes spécifiques à Java+gRPC
  • Je développe des API depuis longtemps, j’ai utilisé à la fois gRPC et HTTP/REST, et j’ai aussi publié la bibliothèque https://github.com/oapi-codegen/oapi-codegen, qui génère des clients et serveurs Go à partir de spécifications OpenAPI
    J’ai du mal à adhérer à la façon dont l’article distingue OpenAPI et REST. OpenAPI est une manière de documenter le comportement d’une API HTTP, et peut représenter aussi bien une API RESTful qu’une API totalement arbitraire. En tant que langage de schéma décrivant une API de façon interprétable par des outils, c’est conceptuellement proche des fichiers Protocol Buffer qui définissent un protocole gRPC
    gRPC est un mécanisme RPC qui échange des proto ; lorsque Google a publié protobuf, il n’a pas ouvert Stubby, sa couche RPC interne, et gRPC n’est pas aussi bon que Stubby. Il reste toutefois très efficace côté transport et relativement facile à étendre
    Cela dit, gRPC ne dispose pas d’un écosystème aussi robuste que les bibliothèques HTTP grand public : il faut souvent implémenter soi-même des middlewares comme le logging ou l’authentification, surtout pour des RPC entre services écrits dans des langages différents
    Pour moi, le vrai problème de gRPC, ce sont les fichiers proto. Tous les clients doivent être construits avec un fichier .proto compatible avec le serveur, ce n’est donc pas un protocole découvrable. Une API HTTP peut être appelée avec curl ou du code écrit à la main même sans description OpenAPI, ce qui rend le couplage plus lâche, et donc le travail comme le débogage plus simples

    • Il existe bien une distinction entre ce que ce blog appelle “OpenAPI” et le vrai REST. En pratique, presque personne ne crée de véritables API REST, la plupart utilisent une approche à la OpenAPI
      Dans la thèse de doctorat de Roy Fielding de 2000, REST était défini ainsi : un GET sur l’URL racine renvoie une réponse 200 OK contenant des liens, et l’on doit pouvoir explorer toutes les ressources proposées par l’API en suivant ces liens. Une structure hiérarchique est autorisée, mais tout doit être accessible quelque part dans l’arborescence de liens ; l’objectif était d’apporter cette découvrabilité
      Dans les faits, presque toutes les entreprises où j’ai travaillé ces vingt dernières années utilisaient soit POST resource_name/resource_id/sub_resource/sub_resource_id/mutation_type, soit PUT resource_name/resource_id/sub_resource/sub_resource_id selon la manière dont l’entreprise gérait l’idempotence, et le client assemblait des URL magiques à partir d’une connaissance structurelle de type Swagger/OpenAPI
      C’est pourquoi les puristes appellent souvent les pratiques réelles “RESTful” plutôt que “REST”, pour signifier qu’elles n’implémentent pas la définition de REST selon Fielding
    • La distinction faite entre OpenAPI et REST m’a aussi semblé confuse. Ce que l’article appelle REST ressemble plutôt à HATEOAS
      En tant que personne qui gère d’assez grosses API avec des clients internes et externes, j’ai aussi du mal à comprendre le flux qui consiste à générer du code à partir d’une spécification OpenAPI. On remplit les stubs générés, puis quand on améliore itérativement la spécification de l’API, l’outil regénère de nouveaux stubs, ce qui impose des fusions manuelles, et plus l’API grossit, plus il devient difficile de retrouver les changements concernés
      J’ai donc créé un monstre qui génère la spécification OpenAPI à partir du code avec go/ast, entre autres. Ce n’est pas parfait, mais c’est une solution à 95 % qui fonctionne avec Echo comme avec Gin ; quand il faut un nouvel endpoint, on crée les structures de requête/réponse et un handler vide, puis on génère la documentation et on l’envoie aux développeurs front-end, ce qui permet d’avancer rapidement
      La plupart des développeurs n’ont pas besoin de se demander comment représenter l’API en OpenAPI, et la documentation reste toujours alignée avec le code
    • Aujourd’hui, il existe gRPC reflection pour la découverte : https://grpc.io/docs/guides/reflection/
    • J’utilise aussi les spécifications OpenAPI pour créer, en plus des types générés, une syntaxe de requête proche de SQL. Cela permet de manipuler n’importe quelle API tierce avec la même sensation
      Apipe.new(GitHun) |> from("search/repositories") |> eq(:language, "elixir") |> order_by(:updated) |> limit(1) |> execute()
      Pas besoin de connaître les fonctions gRPC disponibles ni les particularités RESTful des API tierces, tout en conservant la documentation intégrée et l’accès typé
      https://github.com/cpursley/apipe
      J’envisage aussi une couche d’adaptation TypeScript pour pouvoir l’intégrer dans des projets JS/TS à la manière de Supabase
      const { data, error } = await apipe.from('search/repositories').eq('language', 'elixir').order_by('updated').limit(1)
      Cet appel peut passer par un proxy Elixir, auquel on confie les tâches lourdes comme le traitement asynchrone ou le rate limiting
    • Dire que gRPC n’est pas un protocole découvrable n’est pas entièrement exact
      On peut produire une description OpenAPI à partir de la sérialisation JSON de Protobuf et la servir avec Swagger, et gRPC lui-même fournit aussi une reflection intégrée ainsi que l’utilitaire grpcurl qui l’exploite
  • Pour avoir travaillé dans quelques entreprises FAANG, Thrift/gRPC est vraiment utile pour le routage des services internes.
    Cela dit, une grande partie de cette complexité est prise en charge par les équipes qui créent les bibliothèques, les couches de découverte de services, le routage, etc. Avec un protocole RPC, ces choses deviennent possibles à une échelle et à une vitesse difficiles à atteindre avec des services JSON/REST classiques.
    Je n’ai jamais vu non plus une API REST qui ne laisse pas transparaître des verbes, et si je devais créer un service mesh backend ou relier deux services locaux via un flux réseau, je choisirais toujours gRPC.
    Mais je n’utiliserais jamais gRPC pour une exposition aux clients ou au web. RPC est puissant parce qu’il fige beaucoup de décisions et impose « une seule façon » de faire. À l’inverse, si des clients variés, dans plusieurs piles technologiques, doivent consommer le service, REST est bien meilleur.

    • Je ne le ferais pas pour une API publique, mais pour une API privée je fais simplement un POST /api/doThingy avec un corps JSON.
      C’est du RPC facile, auquel n’importe qui peut participer avec le client HTTP le plus basique, et cela fonctionne bien sur tous les OS et navigateurs. Pas besoin de se battre pour savoir s’il faut mettre une donnée dans le chemin de l’URL, dans les paramètres de requête ou dans le corps.
      Si l’on utilise des familles de serveurs qui cherchent à rendre ça moins pénible, comme Buf ou Connect, gRPC accepte volontiers du JSON via HTTP.
    • Je me demande ce qu’il en est des applications client/serveur qui ne sont pas web.
      Je pense à des cas comme les jeux en ligne ou les MMO, où il faut des communications bien plus temps réel qu’avec REST, mais je ne sais pas trop si, aujourd’hui, on empile quelque chose par-dessus une connexion socket.
    • Si Thrift/gRPC est une bénédiction pour le routage des services internes, je me demande par rapport à quoi.
      J’aimerais aussi savoir quelles autres solutions vous avez essayées.
    • Je me demande ce que signifie « les verbes transparaissent ».
  • Si vous ne faites pas de streaming bidirectionnel, gRPC est généralement une perte de temps, à mon avis.
    Il y a l’enfer des dépendances transitives à l’exécution, l’enfer de la chaîne d’outils, et même les équipes qui maintiennent les différentes implémentations en interne chez Google semblent ne pas être philosophiquement d’accord sur la façon dont les fonctionnalités de base devraient fonctionner.
    Essayez d’exposer une API gRPC à une équipe qui n’utilise pas votre langage, surtout si ce n’est pas Go/Python/Java ou même si elle utilise une vieille version de ceux-ci, de l’intégrer à un produit commercial prêt à l’emploi, ou de l’exposer au navigateur : dans tous les cas, il faut une couche intermédiaire.

    • J’ai utilisé gRPC dans plusieurs entreprises et équipes, avec en gros 100 à 500 ingénieurs par entreprise, et je n’ai pas rencontré de problèmes de dépendances ni de chaîne d’outils.
      gRPC s’est globalement bien passé.
    • Je pense qu’il ne faut pas l’exposer directement au navigateur. Ce n’est pas le domaine où gRPC excelle, et il vaut mieux créer une couche personnalisée qui convertit en JSON.
      Utiliser REST pour faire communiquer des services backend entre eux n’a pas non plus grand intérêt s’il y a des exigences de performance, et à moins qu’il ne s’agisse d’appels occasionnels récupérant de petites quantités de données, il y a peu de raisons d’utiliser un protocole ou une API lisible par des humains.
    • Je me souviens avoir essayé d’exposer une API gRPC au navigateur et m’être fait reprocher de ne pas avoir créé une interface « façon JSON ».
      Quand on renvoyait un type parmi les sous-types oneof qui n’avait pas encore de champ, la conversion automatique produisait quelque chose comme { "id": "id", "sub_type_two": { } }.
      Fonctionnellement, ça marchait, et même si des champs étaient ajoutés plus tard, ce code continuerait à fonctionner. Mais dans le monde du web, représenter le type de réponse par un objet vide est étrange, et ce genre de problème peut ne pas être très visible quand on écrit du protobuf.
    • Le streaming bidirectionnel est généralement une mauvaise idée pour quelque chose que l’on veut exploiter « à grande échelle ».
    • Protobuf n’est pas adapté au streaming.
      Comparé à presque n’importe quel protocole binaire imaginable, c’est quasiment anti-streaming.
  • Ma seule expérience de gRPC en entreprise était un projet poussé par un autre développeur senior au motif qu’« il fallait de la performance ».
    Au final, comme il fallait que le frontend puisse le consommer, nous avons aussi créé une API JSON, et personne à part ce développeur n’avait d’expérience avec gRPC. Même lui n’était pas allé plus loin que le guide de démarrage rapide de gRPC Python et n’a pas aidé à corriger les bugs.
    Le projet était un désastre pour de nombreuses raisons, et n’a jamais approché une échelle qui aurait justifié gRPC.
    Cela dit, le peu de gRPC que j’ai utilisé personnellement m’a plu, et j’ai l’impression qu’il demande beaucoup plus de travail et de réflexion. C’est peut-être aussi parce que j’ai beaucoup plus d’expérience avec les API JSON.

    • Cela ressemble davantage à une critique du développeur « senior » qui ne savait même pas, avant l’adoption, que ce n’était pas compatible avec les navigateurs, qu’à une critique de gRPC lui-même.
  • J’utilise ConnectRPC https://connectrpc.com/ avec plaisir.
    Il corrige beaucoup des aspects problématiques de gRPC, et j’espère que lorsque Safari adoptera WebTransport, ConnectRPC pourra développer un meilleur streaming.
    Au début, je trouvais https://buf.build excessif, mais la possibilité d’importer des fichiers proto tiers sans avoir à les télécharger un par un a été décisive.
    deps:
    - buf.build/landeed/protopatch
    - buf.build/googleapis/googleapis
    La génération automatique de SDK compte aussi beaucoup. Avant, j’aurais voulu saluer la génération automatique de SDK pour environ 9 langages, mais une mise à jour est arrivée ces deux derniers jours et on voit maintenant 16 langages, plus OpenAPI et d’autres nouvelles fonctionnalités.
    Moi aussi, je me suis laissé séduire par les fausses promesses du streaming gRPC, et ce document correspond exactement à mon expérience : https://connectrpc.com/docs/go/streaming/

    • J’ai créé un petit wrapper basé sur WebSocket pour le streaming ConnectRPC afin de le faire fonctionner avec ReactNative.
      Grâce à cela, on peut aussi utiliser le streaming bidirectionnel dans le navigateur.
    • Cela dit, on utilise toujours Protocol Buffers, et beaucoup des problèmes que je rencontre avec gRPC viennent précisément de là.
    • Je me demande s’il y a des nouvelles récentes concernant la prise en charge de WebTransport par Safari.
  • On a l’impression que Google a mené une sorte de guerre psychologique contre tout le secteur pour pousser à utiliser gRPC dans les communications entre services internes.
    L’expérience développeur de gRPC est nettement moins bonne que celle de REST.
    On ne peut pas donner à quelqu’un une simple commande pour appeler un endpoint, il faut des outils supplémentaires non standardisés. En plus, le code côté client généré est, dans n’importe quel langage, un amas d’une laideur rare.

    • Du point de vue backend, je suis fortement en désaccord avec l’idée que l’expérience développeur de gRPC serait moins bonne que celle de REST.
      Un simple changement de protocole permet de savoir statiquement quels consommateurs en aval doivent être mis à jour et redéployés, ce qui peut transformer plusieurs semaines de travail en une modification d’une heure.
      On sait aussi que les messages acceptés et émis sont validés immédiatement, et qu’on peut les stocker à faible coût pour les restaurer plus tard.
      Avec proto, on obtient une documentation d’API très lisible, qui n’est pas noyée dans le code ou la logique métier. La gestion des versions et la sémantique de dépréciation sont aussi intégrées, et, à l’exception des maps, les structures de données prises en charge sont plus riches.
      En comparaison, JSON paraît gonflé et vieilli côté backend.
    • gRPC est un standard sur les points importants.
      On décrit les types de données et les signatures de fonctions, puis on obtient quelque chose qu’on peut appeler comme de vraies fonctions, ce qui permet de se concentrer sur la logique métier plutôt que sur le boilerplate de sérialisation/désérialisation.
      Thrift est également bien meilleur que tout faire soi-même, et je pense que GraphQL est encore meilleur.
    • Je l’ai utilisé sous contrainte dans plusieurs entreprises, mais dans 99 % des cas c’était un investissement en dette technique inutile.
      Même avec Go, comprendre la régénération et la gestion des versions de proto partagés est pénible, et ça empire à chaque nouveau langage ajouté.
      Pourtant, toutes les startups semblent penser qu’elles ont besoin de 100 microservices et de gRPC.
  • La phrase selon laquelle « si l’API est une API REST, le client n’a pas besoin de comprendre le format des URL, et ce format ne fait pas partie de la spécification d’API fournie au client » rejoint la définition de REST par Roy Fielding.
    Fielding a écrit qu’une API REST devait être abordée sans connaissance préalable autre qu’un URI initial et un ensemble de types de médias standardisés, puis que toutes les transitions d’état applicatif devaient ensuite se faire par le client choisissant parmi les options fournies par le serveur.
    https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypert...
    Le sujet a déjà été abondamment traité, mais il reste intéressant de constater que, dans un vrai système RESTful, la « spécification d’API » fournie au client ne devrait être que l’URI/URL du point d’entrée initial.

    • L’idée d’un REST auto-descriptif est désormais mieux connue sous le nom de HATEOAS.
      Personnellement, je trouve cela lourd et peu utile pour résoudre de vrais problèmes.
      https://en.m.wikipedia.org/wiki/HATEOAS
    • Je me demande comment on écrit un client d’API pour une API REST qui n’expose que le point d’entrée initial.
      En particulier, je ne vois pas comment le client est censé découvrir les ressources manipulables ou les modèles de requête/réponse.
    • Je ne suis pas entièrement d’accord avec l’idée que, dans un vrai système RESTful, la spécification d’API fournie au client devrait se limiter à l’URI/URL du point d’entrée initial.
      Pour la configuration, peut-être, mais la spécification d’API doit aller bien au-delà de l’URL et décrire en détail les types de médias utilisés par le système. Autrement dit, il faut surtout décrire les corps des requêtes/réponses HTTP.
      Le lien dit aussi qu’« une API REST doit consacrer presque tout son effort descriptif à définir les types de médias utilisés pour représenter les ressources et piloter l’état applicatif ».
      Au final, on ne renvoie pas seulement application/json, mais plutôt quelque chose comme un +json spécifique, et la plupart du temps ce n’est pas du JSON générique, mais des données métier que l’application doit comprendre.
      Dans les discussions grand public, l’attention se concentre uniquement sur l’URL initiale, et la majeure partie du travail dont parlait Fielding — « décrire les types de médias » — disparaît. Il est donc naturel que quelqu’un qui entend « une seule URL suffit » demande : « où est le reste de la spécification ? »
    • Les deux disent en fait la même chose. Ici, le « format de l’URL » désigne littéralement le format de l’URL, pas le format de la ressource.
      Moi aussi, j’ai cliqué en pensant encore tomber sur un blogueur qui n’avait pas compris REST, mais l’auteur semble au moins connaître les concepts de base.
      J’aime aussi gRPC, et il est assez séduisant pour des projets commerciaux, mais pour un projet personnel ou idéaliste, je pense que REST est préférable.
    • C’est un exemple typique d’une bonne idée devenue populaire, puis propagée par des gens qui l’ont mal comprise.
  • Je n’aime pas utiliser gRPC à l’intérieur d’un datacenter.
    On le choisit pour des raisons de performance, mais gRPC n’est pas vraiment ce que j’appellerais très performant, et la qualité des clients publics est très faible, surtout en dehors des implémentations cœur C++/Java. L’implémentation Node.js en est un exemple.
    Je ne suis pas opposé à l’utilisation de protobuf comme spécification d’API, mais il faudrait pouvoir l’utiliser avec un protocole de framing au-dessus de TCP. Cela dit, pour ce type de RPC, il n’existe pas vraiment de choix clairement dominant.
    Pour les API web, je préfère des payloads lisibles, mais en général on utilise JSON avec une spécificité de types relâchée, ce qui crée des problèmes d’interopérabilité entre langages backend. Dans Node.js en particulier, JSON.parse est utilisé comme s’il s’agissait d’une implémentation de mapping de schéma.
    Pour bien faire les choses, il faudrait générer explicitement encodeurs et décodeurs à partir du schéma, ce qui réduit en partie l’intérêt d’utiliser JSON dans un contexte JS.

    • Si les performances vous préoccupent au point d’envisager gRPC, je me demande pourquoi il serait en même temps acceptable de garder Node.js près de votre stack.
    • D’accord, et pour le problème des schémas en JS, Zod aide beaucoup.
      Je surveille aussi le projet TypeSpec de Microsoft : typespec.io
    • Le principal avantage de proto est l’interopérabilité entre plusieurs langages.
      Si votre stack technique est monolangage, son importance diminue. Et si vous utilisez autre chose que les principaux langages de Google, il y a de fortes chances que l’expérience soit moins bonne.
    • En 2023, il y a eu une présentation sur Homa, un protocole non basé sur TCP pour le RPC en datacenter : https://youtu.be/xQQT8YUvWg8?si=g3u5TogBe0_QpPpj
  • gRPC a semblé inutilement peu accessible pour le reste du monde en dehors de Google
    Le client gRPC JS est inutilement lourd et assez opaque. L’idée est bonne, mais l’exécution laisse à désirer par rapport à ce à quoi sont habitués les gens avec la « simplicité » de REST

    • À la frontière frontend/backend, le camp REST/JSON et le camp RPC/protobuf/gRPC s’opposent
      RPC est sémantiquement plus maintenable, car il n’oblige pas à faire entrer de force la cardinalité ou les relations du modèle de données dans un schéma prescriptif unique. Dans un monde où les API évoluent vite, il est difficile de viser de belles entités RESTful ; avec de grandes équipes et des exigences/propriétés qui changent, une conception centrée sur les services est préférable
      Côté frontend, on ne maintient pas les systèmes backend. On veut des API faciles à comprendre et des entités que l’on puisse abstraire avec REST. C’est le bénéficiaire final de ce type de conception
      L’effort nécessaire pour REST a du sens dans les entreprises qui vendent des API et dont les développeurs tiers sont les principaux clients
      Pour le développement backend, protobuf et un encodage binaire sur le fil sont plus simples. On peut définir une API et la partager entre services de façon typée statiquement, tout en réduisant le temps d’encodage/décodage des messages. JSON n’est ni sémantique ni typé, et ajoute aussi beaucoup d’overhead
      À l’inverse, le frontend manipule nativement le texte et JSON. Il ne veut pas télécharger des définitions protobuf ni traiter des données binaires comme des citoyens de seconde zone, et cela ne s’intègre pas proprement aux outils
      gRPC intègre bien le routage, les retries, les canaux auxiliaires, le streaming et la sémantique de dépréciation des protocoles, mais cela n’apparaît presque pas côté frontend. Tout cela est destiné aux consommateurs backend
      Au final, c’est à 100 % un écart d’outillage frontend/backend, et un décalage entre interface et utilisabilité
    • REST ressemble à HTML
      Par défaut, on peut en voir la source, c’est lisible par un humain et facile à inspecter
      gRPC sert à faire communiquer efficacement des machines entre elles ; dès qu’un humain intervient, que ce soit pour coder ou pour inspecter les requêtes/réponses, cela devient un peu inconfortable
      Comme les contextes et les objectifs étaient différents, cette différence d’utilisabilité se comprend
    • L’implémentation officielle de gRPC pour JavaScript n’est pas terrible
      À mon avis, l’implémentation de buf.build est bonne
      https://buf.build/blog/protobuf-es-the-protocol-buffers-type...
    • gRPC est une bonne idée, mais il s’est alourdi avec des solutions à des problèmes à la Google que je n’ai pas
      Beaucoup semblent l’avoir choisi parce qu’ils avaient besoin d’un protocole du type RPC binaire avec contrat, mais plus on s’éloigne de GoLang, plus cela se dégrade
    • Il existe des cas où gRPC brille. Le streaming en fait partie : il permet d’envoyer de façon transparente un flux de messages au sein d’une même « connexion »
      Pour un simple service CRUD, REST suffit largement