💻 Développement

grpc-service-designer

Conception de services gRPC, définition de contrats Protobuf, patterns de streaming et intégration dans des architectures microservices.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- grpc-service-designer --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } grpc-service-designer -Launch"

🚀 Déjà installé ?

claude "/grpc-service-designer"

Ou tapez /grpc-service-designer dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

gRPCprotobuffichier protostreaming gRPCservice gRPCcontrat protobuf

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/dev-skills/grpc-service-designer ~/.claude/skills/

Source : dev-skills/grpc-service-designer

📖 Manuel

Concepteur de Services gRPC

Workflow

  1. Comprendre le besoin : identifier le type de communication (unaire, streaming serveur, streaming client, bidirectionnel).
  2. Concevoir le contrat : définir les messages et services dans un fichier .proto.
  3. Implémenter : proposer le code serveur et client adapté au langage.
  4. Valider : vérifier la compatibilité, la gestion d'erreurs et la performance.

Types de communication gRPC

TypeUsageExemple
UnaireRequête/réponse classiqueCRUD, authentification
Server streamingServeur envoie un fluxNotifications, feeds temps réel
Client streamingClient envoie un fluxUpload de fichiers, logs batch
BidirectionnelFlux dans les deux sensChat, jeux en ligne, monitoring

Conception de contrats Protobuf

Structure d'un fichier .proto

syntax = "proto3";

package myapp.payments.v1;

option csharp_namespace = "MyApp.Payments.V1";

import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";

// Service de gestion des paiements
service PaymentService {
  // Créer un paiement (unaire)
  rpc CreatePayment(CreatePaymentRequest) returns (PaymentResponse);

  // Suivre le statut en temps réel (server streaming)
  rpc WatchPaymentStatus(WatchPaymentRequest) returns (stream PaymentStatusUpdate);

  // Envoyer des transactions par lot (client streaming)
  rpc BatchTransactions(stream TransactionRequest) returns (BatchTransactionResponse);
}

message CreatePaymentRequest {
  string idempotency_key = 1;
  int64 amount_cents = 2;
  string currency = 3;
  string recipient_id = 4;
  map<string, string> metadata = 5;
}

message PaymentResponse {
  string payment_id = 1;
  PaymentStatus status = 2;
  google.protobuf.Timestamp created_at = 3;
}

enum PaymentStatus {
  PAYMENT_STATUS_UNSPECIFIED = 0;
  PAYMENT_STATUS_PENDING = 1;
  PAYMENT_STATUS_PROCESSING = 2;
  PAYMENT_STATUS_COMPLETED = 3;
  PAYMENT_STATUS_FAILED = 4;
}

Conventions de nommage

ÉlémentConventionExemple
Packagecompany.service.v1myapp.payments.v1
ServicePascalCase + ServicePaymentService
RPCPascalCase, verbe d'actionCreatePayment
MessagePascalCase + Request/ResponseCreatePaymentRequest
Champsnake_casepayment_id
EnumSCREAMING_SNAKE_CASE avec préfixePAYMENT_STATUS_PENDING
Enum valeur 0Toujours UNSPECIFIEDPAYMENT_STATUS_UNSPECIFIED

Implémentation C# / ASP.NET

Serveur gRPC

public class PaymentServiceImpl : PaymentService.PaymentServiceBase
{
    private readonly IPaymentRepository _repo;

    public override async Task<PaymentResponse> CreatePayment(
        CreatePaymentRequest request, ServerCallContext context)
    {
        // Vérifier l'idempotence
        var existing = await _repo.FindByIdempotencyKey(request.IdempotencyKey);
        if (existing != null)
            return MapToResponse(existing);

        var payment = new Payment
        {
            Amount = request.AmountCents,
            Currency = request.Currency,
            RecipientId = request.RecipientId
        };

        await _repo.CreateAsync(payment);
        return MapToResponse(payment);
    }

    public override async Task WatchPaymentStatus(
        WatchPaymentRequest request,
        IServerStreamWriter<PaymentStatusUpdate> responseStream,
        ServerCallContext context)
    {
        while (!context.CancellationToken.IsCancellationRequested)
        {
            var status = await _repo.GetStatus(request.PaymentId);
            await responseStream.WriteAsync(new PaymentStatusUpdate
            {
                PaymentId = request.PaymentId,
                Status = status
            });

            if (status is PaymentStatus.Completed or PaymentStatus.Failed)
                break;

            await Task.Delay(1000, context.CancellationToken);
        }
    }
}

Enregistrement dans ASP.NET

// Program.cs
builder.Services.AddGrpc(options =>
{
    options.MaxReceiveMessageSize = 4 * 1024 * 1024; // 4 MB
    options.EnableDetailedErrors = builder.Environment.IsDevelopment();
    options.Interceptors.Add<LoggingInterceptor>();
});

app.MapGrpcService<PaymentServiceImpl>();

Bonnes pratiques

Versionning

Performance

Gestion d'erreurs

Règles