gRPC en Go : RPC moderne pour microservices — tutoriel 2026
Article principal du cluster : Web 2026 sans framework lourd : HTMX, Hotwire, Alpine.js
Cet article fait partie du cluster Web Moderne 2026. Pour la vue d’ensemble des architectures backend légères et performantes, commencez par lire le pilier.
Introduction
Imaginez deux services qui se parlent en production. Le premier envoie une requête REST/JSON : il sérialise un objet en texte, l’emballe dans un body HTTP/1.1, attend la connexion TCP, transmet 840 octets, et attend la réponse. Le second utilise gRPC : il sérialise le même objet en binaire Protocol Buffers sur une connexion HTTP/2 persistante, transmet 120 octets, et reçoit la réponse dans la même connexion multiplexée. C’est le delta quotidien que vivent des milliers d’équipes ayant migré de REST à gRPC.
gRPC — Google Remote Procedure Call — est un framework RPC open-source initialement développé par Google, aujourd’hui maintenu par la Cloud Native Computing Foundation (CNCF). Il repose sur deux standards : HTTP/2 comme transport (multiplexage, compression d’en-têtes, streams bidirectionnels) et Protocol Buffers v3 comme format de sérialisation (binaire, fortement typé, compact). La combinaison produit des appels inter-services jusqu’à sept fois plus rapides que REST/JSON dans les scénarios de charge élevée, selon les benchmarks publiés dans l’écosystème grpc-ecosystem.
L’autre avantage structurant de gRPC est son caractère multi-langage : on définit le contrat de service une seule fois dans un fichier .proto, et les stubs client/serveur sont générés automatiquement pour Go, Python, Java, Node.js, Rust, C++, Dart, Kotlin et une vingtaine d’autres langages. Un service Go peut donc appeler un service Python sans écrire une ligne de glue manuelle. Dans un contexte de PME africaine qui construit progressivement son système d’information, cette interopérabilité est précieuse.
Ce tutoriel vous amène de zéro à un service gRPC Go complet avec TLS et authentification, en sept étapes progressives. À la fin, vous disposerez d’un template réutilisable pour vos propres microservices.
Prérequis
- Go 1.22+ installé — vérifier avec
go version(téléchargement sur go.dev/dl) - protoc — le compilateur Protocol Buffers (installé via le gestionnaire de paquets de votre OS ou depuis github.com/protocolbuffers/protobuf/releases)
- protoc-gen-go et protoc-gen-go-grpc — les deux plugins Go pour protoc
- Un terminal Unix ou WSL sous Windows
- Niveau intermédiaire en Go (modules, goroutines de base)
- Temps estimé : 40 minutes
Pour installer les plugins protoc une fois Go configuré, deux commandes suffisent :
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Après l’installation, vérifiez que $GOPATH/bin (généralement ~/go/bin) est bien dans votre $PATH. Un which protoc-gen-go doit renvoyer un chemin valide. Si la commande est introuvable, ajoutez export PATH="$PATH:$(go env GOPATH)/bin" à votre ~/.bashrc ou ~/.zshrc.
Étape 1 — gRPC vs REST : choisir le bon outil
Avant d’ouvrir un éditeur, il est utile de comprendre pourquoi gRPC existe et dans quel contexte il l’emporte sur REST. REST est un style architectural qui impose peu de contraintes : n’importe quel verbe HTTP, n’importe quel format de sérialisation, n’importe quelle structure d’URL. Cette flexibilité est une force pour les API publiques orientées navigateur — mais devient un fardeau dans les communications internes entre microservices, où la flexibilité se transforme en hétérogénéité non contrôlée et en overhead inutile.
gRPC inverse les priorités : le contrat est défini en premier (le fichier .proto), le code est généré, et toute déviation est une erreur de compilation. On gagne en cohérence, en performance et en outillage. En contrepartie, gRPC est moins adapté aux API publiques consommées directement par des navigateurs (HTTP/2 avec trailers n’étant pas exposé nativement par le fetch standard — le projet gRPC-Web comble partiellement ce vide, cf. section Adaptation ouest-africaine).
Le tableau ci-dessous résume les cas d’usage :
| Critère | REST/JSON | gRPC/Protobuf |
|---|---|---|
| API publique navigateur | Idéal | Nécessite gRPC-Web |
| Communication interne services | Acceptable | Idéal |
| Streaming temps réel | SSE ou WebSocket (séparé) | Natif (4 types de streams) |
| Contrat fort typé | OpenAPI (optionnel) | Obligatoire (.proto) |
| Taille payload | 100% (référence) | ~14% à ~30% selon charge |
| Débogage humain | Facile (curl, Postman) | Nécessite grpcurl ou Evans |
Pour votre architecture microservices interne — ERP, passerelle paiement, service de notification — gRPC est le choix naturel dès que vous avez deux services Go qui se parlent plus de quelques dizaines de fois par seconde.
Étape 2 — Définir un service avec un fichier .proto
Tout commence par le fichier .proto, qui est le contrat de votre service. Ce fichier est indépendant du langage : il décrit les messages échangés (équivalent aux structs) et les procédures disponibles (équivalent aux fonctions). Une fois ce fichier écrit et validé, il devient la source de vérité partagée entre toutes les équipes qui implémentent ou consomment le service.
Créez la structure de projet suivante :
mkdir grpc-demo && cd grpc-demo
go mod init grpc-demo
mkdir -p proto/payment server client
Puis créez le fichier proto/payment/payment.proto :
syntax = "proto3";
package payment;
// L'option go_package indique où placer le code Go généré
option go_package = "grpc-demo/proto/payment";
// Message pour initier un paiement
message PaymentRequest {
string order_id = 1;
double amount = 2;
string currency = 3; // "XOF", "XAF", "GNF"
string provider = 4; // "wave", "cinetpay", "orange_money"
}
// Message de réponse
message PaymentResponse {
string transaction_id = 1;
string status = 2; // "pending", "success", "failed"
string message = 3;
}
// Message pour le streaming : événements de statut en temps réel
message PaymentEvent {
string order_id = 1;
string status = 2;
int64 timestamp = 3;
}
// Définition du service avec ses quatre méthodes
service PaymentService {
// RPC unaire classique : 1 requête, 1 réponse
rpc ProcessPayment(PaymentRequest) returns (PaymentResponse);
// Server-side streaming : 1 requête, flux de réponses
rpc TrackPayment(PaymentRequest) returns (stream PaymentEvent);
// Bidirectional streaming : flux de requêtes ET de réponses
rpc BatchProcess(stream PaymentRequest) returns (stream PaymentResponse);
}
Quelques points importants sur la syntaxe. Les champs sont numérotés (= 1, = 2…) : ces numéros sont les identifiants de champ dans l’encodage binaire Protobuf. Ils ne doivent jamais être réutilisés une fois le service en production, même si un champ est supprimé — une réutilisation casserait la compatibilité avec les clients déployés. Le mot-clé stream avant un type de message active le streaming dans la direction concernée. Ici on définit les trois modes les plus utiles : unaire, server-streaming et bidirectionnel.
Étape 3 — Générer le code Go avec protoc
Le fichier .proto est un contrat déclaratif. Pour pouvoir l’utiliser en Go, il faut le compiler avec protoc et ses deux plugins. Cette étape génère automatiquement les structs Go correspondant aux messages, ainsi que les interfaces de serveur et les stubs de client. C’est du code que vous n’avez pas à écrire ni maintenir manuellement.
Depuis la racine du projet :
protoc \
--go_out=. \
--go_opt=paths=source_relative \
--go-grpc_out=. \
--go-grpc_opt=paths=source_relative \
proto/payment/payment.proto
Cette commande invoque protoc avec deux plugins en parallèle : --go_out génère les structs Go via protoc-gen-go, et --go-grpc_out génère les interfaces et stubs gRPC via protoc-gen-go-grpc. L’option paths=source_relative place les fichiers générés relativement au fichier .proto source. Après exécution, vous trouvez deux nouveaux fichiers dans proto/payment/ : payment.pb.go (les structs) et payment_grpc.pb.go (les interfaces de service). Ces fichiers sont entièrement générés — ne les éditez jamais à la main.
Installez ensuite le module grpc-go officiel :
go get google.golang.org/grpc@latest
go get google.golang.org/protobuf@latest
Étape 4 — Implémenter le serveur Go
Le code généré à l’étape précédente définit une interface Go que votre serveur doit implémenter. C’est le contrat côté serveur : si une méthode manque, le compilateur Go vous le signale immédiatement. Cette approche est fondamentalement différente de REST où un endpoint manquant n’est détecté qu’à l’exécution, voire en production.
Créez server/main.go :
package main
import (
"context"
"fmt"
"io"
"log"
"net"
"time"
"google.golang.org/grpc"
pb "grpc-demo/proto/payment"
)
// paymentServer implémente l'interface PaymentServiceServer générée
type paymentServer struct {
pb.UnimplementedPaymentServiceServer
}
// ProcessPayment : RPC unaire
func (s *paymentServer) ProcessPayment(
ctx context.Context,
req *pb.PaymentRequest,
) (*pb.PaymentResponse, error) {
log.Printf("Paiement reçu : order=%s montant=%.2f %s via %s",
req.OrderId, req.Amount, req.Currency, req.Provider)
// Simulation d'un appel au provider réel (Wave, CinetPay…)
transactionID := fmt.Sprintf("TXN-%s-%d", req.OrderId, time.Now().UnixMilli())
return &pb.PaymentResponse{
TransactionId: transactionID,
Status: "pending",
Message: "Paiement initié avec succès",
}, nil
}
// TrackPayment : server-side streaming
func (s *paymentServer) TrackPayment(
req *pb.PaymentRequest,
stream pb.PaymentService_TrackPaymentServer,
) error {
statuses := []string{"pending", "processing", "success"}
for _, status := range statuses {
if err := stream.Send(&pb.PaymentEvent{
OrderId: req.OrderId,
Status: status,
Timestamp: time.Now().UnixMilli(),
}); err != nil {
return err
}
time.Sleep(500 * time.Millisecond) // Simulation latence provider
}
return nil
}
// BatchProcess : streaming bidirectionnel
func (s *paymentServer) BatchProcess(
stream pb.PaymentService_BatchProcessServer,
) error {
for {
req, err := stream.Recv()
if err == io.EOF {
return nil // Le client a fermé son stream
}
if err != nil {
return err
}
// Répondre immédiatement pour chaque requête reçue
err = stream.Send(&pb.PaymentResponse{
TransactionId: fmt.Sprintf("TXN-%s", req.OrderId),
Status: "queued",
Message: "Traitement en file d'attente",
})
if err != nil {
return err
}
}
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("Écoute impossible : %v", err)
}
grpcServer := grpc.NewServer()
pb.RegisterPaymentServiceServer(grpcServer, &paymentServer{})
log.Println("Serveur gRPC démarré sur :50051")
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("Erreur serveur : %v", err)
}
}
Remarquez l’embed de pb.UnimplementedPaymentServiceServer dans la struct paymentServer. Ce pattern, recommandé par le projet grpc-go, fournit des implémentations par défaut pour toutes les méthodes de l’interface — celles qui retournent codes.Unimplemented. Ainsi, si vous ajoutez demain une nouvelle méthode au fichier .proto et régénérez le code, votre serveur continue de compiler même avant que vous ayez implémenté la nouvelle méthode. C’est de la sécurité à la compilation, pas une facilité de développement.
Lancez le serveur avec go run server/main.go. Vous devriez voir Serveur gRPC démarré sur :50051 dans le terminal. Le serveur écoute maintenant sur le port 50051 (port conventionnel pour gRPC en développement).
Étape 5 — Implémenter le client Go
Le client gRPC est remarquablement simple à écrire, précisément parce que le stub généré à l’étape 3 ressemble à un objet Go ordinaire avec des méthodes typées. Il n’y a pas de parsing de JSON, pas de construction manuelle d’URL, pas de gestion des codes HTTP — le stub s’occupe de tout le transport pour vous.
Créez client/main.go :
package main
import (
"context"
"io"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
pb "grpc-demo/proto/payment"
)
func main() {
// grpc.NewClient remplace grpc.Dial (deprecated depuis grpc-go v1.58)
conn, err := grpc.NewClient(
"localhost:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
log.Fatalf("Connexion impossible : %v", err)
}
defer conn.Close()
client := pb.NewPaymentServiceClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// --- RPC unaire ---
resp, err := client.ProcessPayment(ctx, &pb.PaymentRequest{
OrderId: "ORD-2026-001",
Amount: 5000,
Currency: "XOF",
Provider: "wave",
})
if err != nil {
log.Fatalf("ProcessPayment échoué : %v", err)
}
log.Printf("Réponse : txn=%s status=%s", resp.TransactionId, resp.Status)
// --- Server-side streaming ---
stream, err := client.TrackPayment(ctx, &pb.PaymentRequest{
OrderId: "ORD-2026-001",
})
if err != nil {
log.Fatalf("TrackPayment échoué : %v", err)
}
for {
event, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("Stream error : %v", err)
}
log.Printf("Événement : order=%s status=%s", event.OrderId, event.Status)
}
}
Notez l’usage de grpc.NewClient au lieu de l’ancien grpc.Dial. La différence fonctionnelle est subtile mais importante : NewClient ne tente pas la connexion TCP immédiatement à l’appel — il initialise le canal de manière lazy. La connexion réelle est établie lors du premier appel RPC. Ce comportement est plus cohérent avec la sémantique d’un pool de connexions et évite les erreurs de démarrage en ordre incorrect dans un environnement Docker Compose où les services ne démarrent pas toujours dans le bon ordre.
Dans un second terminal, lancez go run client/main.go pendant que le serveur tourne. Vous observerez les logs des deux côtés : côté serveur, les lignes Paiement reçu, et côté client, la réponse suivie des trois événements de tracking espacés de 500 ms.
Étape 6 — Streaming bidirectionnel
Le streaming bidirectionnel est la fonctionnalité qui différencie le plus gRPC de REST. Dans un flux bidirectionnel, client et serveur peuvent envoyer des messages indépendamment et simultanément sur la même connexion HTTP/2. C’est l’équivalent d’un WebSocket, mais avec un contrat typé et des garanties de fiabilité supérieures. Ce pattern est particulièrement utile pour les traitements par lots, les dashboards temps réel ou les pipelines de données.
Ajoutez une fonction batchDemo dans client/main.go pour illustrer le flux bidirectionnel :
func batchDemo(client pb.PaymentServiceClient) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Ouvrir le stream bidirectionnel
stream, err := client.BatchProcess(ctx)
if err != nil {
log.Fatalf("BatchProcess stream : %v", err)
}
// Goroutine pour recevoir les réponses en parallèle
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
for {
resp, err := stream.Recv()
if err == io.EOF {
return
}
if err != nil {
log.Printf("Recv error : %v", err)
return
}
log.Printf("Batch réponse : txn=%s status=%s", resp.TransactionId, resp.Status)
}
}()
// Envoyer plusieurs requêtes en rafale
orders := []string{"ORD-001", "ORD-002", "ORD-003", "ORD-004", "ORD-005"}
for _, id := range orders {
if err := stream.Send(&pb.PaymentRequest{
OrderId: id,
Amount: 2500,
Currency: "XOF",
Provider: "cinetpay",
}); err != nil {
log.Printf("Send error : %v", err)
break
}
}
// Signaler la fin des envois côté client
stream.CloseSend()
// Attendre que toutes les réponses arrivent
<-doneCh
}
La structure goroutine + channel (doneCh) est le pattern canonique pour le streaming bidirectionnel gRPC en Go. Envoyer et recevoir sont deux opérations bloquantes qui doivent s'exécuter en parallèle — d'où la goroutine dédiée à la réception. Le stream.CloseSend() envoie le signal EOF au serveur (demi-fermeture TCP) : le serveur sait qu'aucune nouvelle requête n'arrivera mais peut encore envoyer des réponses. C'est le mécanisme de grâce qui permet au serveur de terminer son traitement proprement avant de fermer le flux à son tour.
Étape 7 — TLS et interceptors d'authentification
Un service gRPC exposé sans TLS en production est aussi risqué qu'une API REST en HTTP pur. Toutes les données transitent en clair sur le réseau. L'ajout de TLS mutuel (mTLS) est la pratique recommandée pour les communications entre microservices internes : chaque service possède un certificat signé par une CA interne, et les deux parties s'authentifient mutuellement. Pour commencer, un TLS serveur simple est déjà un progrès significatif.
Générez d'abord un certificat auto-signé pour le développement :
openssl req -x509 -newkey rsa:4096 -keyout server.key \
-out server.crt -days 365 -nodes \
-subj "/CN=localhost"
Modifiez ensuite server/main.go pour activer TLS et un interceptor d'authentification par token :
import (
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
// authInterceptor vérifie le token dans les métadonnées gRPC
func authInterceptor(
ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (interface{}, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Error(codes.Unauthenticated, "métadonnées manquantes")
}
tokens := md.Get("authorization")
if len(tokens) == 0 || tokens[0] != "Bearer mon-token-secret" {
return nil, status.Error(codes.Unauthenticated, "token invalide")
}
return handler(ctx, req)
}
// Dans main() :
creds, err := credentials.NewServerTLSFromFile("server.crt", "server.key")
if err != nil {
log.Fatalf("Chargement TLS : %v", err)
}
grpcServer := grpc.NewServer(
grpc.Creds(creds),
grpc.UnaryInterceptor(authInterceptor),
)
Côté client, envoyez le token dans les métadonnées de la requête :
import "google.golang.org/grpc/metadata"
// Créer un contexte enrichi avec le token d'authentification
ctx = metadata.AppendToOutgoingContext(ctx, "authorization", "Bearer mon-token-secret")
L'interceptor unaire s'applique à tous les RPCs unaires du serveur. Pour les méthodes streaming, il existe grpc.StreamInterceptor qui fonctionne sur le même principe mais reçoit un grpc.ServerStream. Dans un système de production, remplacez le token statique par une validation JWT (bibliothèque github.com/golang-jwt/jwt/v5) ou une vérification contre votre service d'identité interne.
Erreurs fréquentes
| Erreur | Cause probable | Solution |
|---|---|---|
protoc-gen-go: program not found |
$GOPATH/bin absent du PATH |
Ajouter export PATH="$PATH:$(go env GOPATH)/bin" au profil shell |
undefined: pb.UnimplementedXxxServer |
Fichier _grpc.pb.go non généré ou plugin protoc-gen-go-grpc manquant |
Vérifier les deux flags --go-grpc_out dans la commande protoc |
transport: error while dialing: connection refused |
Serveur non démarré ou mauvais port | Lancer le serveur en premier, vérifier que le port 50051 est libre (ss -tlnp | grep 50051) |
rpc error: code = Unauthenticated |
Token absent ou mal formaté dans les métadonnées | Vérifier metadata.AppendToOutgoingContext côté client, clé en minuscules obligatoire |
field number X has already been used |
Réutilisation d'un numéro de champ dans le .proto | Utiliser le mot-clé reserved pour les champs supprimés : reserved 3; |
grpc.Dial is deprecated |
Usage de l'ancienne API | Remplacer par grpc.NewClient (grpc-go >= v1.58) |
| Timeout prématuré sur le stream bidirectionnel | context.WithTimeout trop court pour un batch long |
Utiliser context.WithDeadline ou context.Background() avec annulation manuelle |
Adaptation au contexte ouest-africain
Les architectures microservices en Afrique de l'Ouest présentent des contraintes spécifiques que gRPC adresse particulièrement bien. La première est la bande passante. Dans une ville secondaire — Ziguinchor, Bobo-Dioulasso, Labé — une liaison internet dédiée à un serveur d'application peut osciller entre 5 et 20 Mbps avec une latence de 60 à 150 ms vers un VPS régional. Sur ce type de liaison, la réduction de taille payload offerte par Protobuf (en moyenne 70 à 85 % plus compact que JSON pour des objets structurés typiques) n'est pas anecdotique : elle change la capacité de traitement effective du système. Un service de facturation qui envoie 10 000 requêtes par heure économise plusieurs centaines de mégaoctets de transfert par jour.
La deuxième contrainte est l'intégration avec les APIs de paiement mobile comme Wave (Sénégal, Côte d'Ivoire), CinetPay (panafricain), Orange Money ou MTN MoMo. Ces APIs exposent des webhooks REST/JSON vers l'extérieur — vous ne pouvez pas les remplacer par gRPC. L'architecture recommandée est donc hybride : vos microservices internes (service de commandes, service de facturation, service de notifications, service de rapports) communiquent en gRPC entre eux pour la performance, tandis qu'un service payment-gateway dédié fait le pont entre votre réseau gRPC interne et les APIs REST/JSON des providers externes. Ce service gateway est le seul à connaître les détails d'intégration Wave ou CinetPay — les autres services lui envoient juste un ProcessPayment RPC.
Pour les déploiements avec ERPNext (très répandu pour la gestion commerciale en Afrique francophone), Go n'est pas le langage natif — ERPNext est en Python/Frappe. gRPC supporte Python nativement via le package grpcio. Votre module ERPNext personnalisé peut appeler vos microservices Go exactement comme le ferait un client Go, avec le même fichier .proto comme contrat partagé. Générez les stubs Python avec python -m grpc_tools.protoc et le résultat est interopérable sans aucune couche de traduction.
Concernant gRPC-Web : les navigateurs modernes n'exposent pas l'API HTTP/2 avec trailers nécessaire au protocole gRPC natif. Le projet gRPC-Web (github.com/grpc/grpc-web) résout ce problème via un proxy Envoy ou un wrapper HTTP/1.1. Si vos interfaces d'administration ou vos dashboards React/Vue doivent appeler des services gRPC directement depuis le navigateur, gRPC-Web avec Envoy est la solution établie. Pour une PME qui commence, il est souvent plus simple de garder une API REST fine devant le réseau gRPC interne — la porte d'entrée publique reste REST, la plomberie interne passe en gRPC.
Tutoriels frères
- HTMX avec backend Go : HTML over the Wire sans JavaScript framework — construire des interfaces réactives sans SPA, avec Go comme serveur HTMX
- Docker Compose pour microservices Go : orchestration locale en 2026 — mettre en réseau vos services Go + gRPC dans un environnement de développement reproductible
- Alpine.js + HTMX : interactivité légère côté client — compléter votre stack frontend sans React ni Vue
Pour aller plus loin
- Retour au pilier : Web 2026 sans framework lourd : HTMX, Hotwire, Alpine.js
- Documentation officielle gRPC Go : grpc.io/docs/languages/go — guide de démarrage, exemples, meilleures pratiques
- Référence Protocol Buffers v3 : protobuf.dev/programming-guides/proto3
- grpc-go sur GitHub : github.com/grpc/grpc-go — dépôt officiel avec exemples complets dans le dossier
examples/ - grpcurl : github.com/fullstorydev/grpcurl — équivalent de
curlpour gRPC, indispensable pour déboguer en ligne de commande - Evans : github.com/ktr0731/evans — REPL interactif gRPC, excellent pour explorer un service en développement
FAQ
Q : Puis-je utiliser gRPC et REST en même temps sur le même service Go ?
Oui. Le pattern gRPC-gateway (grpc-ecosystem/grpc-gateway) permet de générer automatiquement un proxy REST à partir de votre fichier .proto enrichi d'annotations. Le même service écoute sur deux ports : 50051 pour gRPC, 8080 pour REST/JSON. C'est la solution adoptée par la plupart des équipes qui veulent gRPC en interne et REST vers l'extérieur sans dupliquer la logique métier.
Q : Comment déboguer un appel gRPC sans client Go ?
Utilisez grpcurl. Par exemple : grpcurl -plaintext localhost:50051 payment.PaymentService/ProcessPayment avec un body JSON décrivant le PaymentRequest. Pour que la réflexion fonctionne (et que grpcurl découvre automatiquement les méthodes disponibles), enregistrez le service de réflexion dans votre serveur avec reflection.Register(grpcServer) du package google.golang.org/grpc/reflection. N'activez cette option qu'en développement — en production elle expose le schéma de votre API.
Q : Quelle est la différence entre codes d'erreur gRPC et codes HTTP ?
gRPC définit son propre ensemble de 16 codes d'état dans le package google.golang.org/grpc/codes : OK, Canceled, Unknown, InvalidArgument, NotFound, AlreadyExists, PermissionDenied, Unauthenticated, etc. Ces codes sont transportés dans les trailers HTTP/2 et sont indépendants des codes HTTP. Pour renvoyer une erreur structurée avec des détails, utilisez le package google.golang.org/grpc/status : status.Errorf(codes.NotFound, "commande %s introuvable", orderID).
Q : Comment gérer la compatibilité ascendante quand le .proto évolue ?
Protocol Buffers est conçu pour évoluer sans casser les clients existants, à condition de respecter trois règles : ne jamais changer le numéro d'un champ existant, ne jamais réutiliser un numéro de champ supprimé (utilisez reserved 5, 6; pour bloquer la réutilisation), et ne jamais changer le type d'un champ. Vous pouvez ajouter de nouveaux champs et de nouvelles méthodes sans impact sur les clients qui n'en ont pas connaissance — ils les ignoreront simplement. En revanche, supprimer une méthode sans période de dépréciation cassera les clients qui l'appellent.
Q : gRPC fonctionne-t-il bien avec Kubernetes ?
Oui, mais avec une nuance importante sur le load balancing. Les load balancers L4 classiques (basés sur TCP) ne comprennent pas HTTP/2 et enverront tous les appels gRPC vers le même pod sur une connexion longue durée. La solution est un load balancer L7 comme Istio, Linkerd ou l'Ingress Nginx configuré pour le mode grpc. Alternativement, le load balancing côté client (bibliothèque google.golang.org/grpc/balancer) répartit les appels entre plusieurs connexions maintenues par le client lui-même. Pour un déploiement simple sur VPS sans Kubernetes, ce problème ne se pose pas.
Q : Est-ce que gRPC remplace Kafka ou RabbitMQ pour les événements asynchrones ?
Non. gRPC est synchrone par nature — l'appelant attend la réponse (ou la fin du stream). Pour des communications asynchrones — événements métier, files de messages, pub/sub — un broker de messages comme RabbitMQ, Kafka ou NATS reste la bonne solution. L'architecture typique combine les deux : gRPC pour les appels synchrones entre services (requête-réponse), broker de messages pour les événements asynchrones (notification de paiement confirmé, déclenchement d'un workflow). Ces deux patterns sont complémentaires, pas concurrents.
Site réalisé par [ITS] ITSkillsCenter