# gRPC Integration Overview Expose commands and queries via high-performance gRPC services with automatic code generation. ## What is gRPC Integration? The `Svrnty.CQRS.Grpc` package with `Svrnty.CQRS.Grpc.Generators` source generator provides automatic gRPC service implementations for all registered commands and queries. **Key Features:** - ✅ **Automatic service generation** - Source generators create implementations - ✅ **Google Rich Error Model** - Structured validation errors - ✅ **High performance** - Binary Protocol Buffers - ✅ **Strong typing** - Compile-time safety - ✅ **gRPC reflection** - Tool support (grpcurl, Postman) - ✅ **Bidirectional streaming** - Real-time communication - ✅ **Cross-platform** - Works with any gRPC client ## Quick Start ### Installation ```bash dotnet add package Svrnty.CQRS.Grpc dotnet add package Svrnty.CQRS.Grpc.Generators dotnet add package Grpc.AspNetCore ``` ### Basic Setup **1. Define .proto file:** ```protobuf syntax = "proto3"; package myapp; import "google/protobuf/empty.proto"; service CommandService { rpc CreateUser (CreateUserCommand) returns (CreateUserResponse); rpc DeleteUser (DeleteUserCommand) returns (google.protobuf.Empty); } service QueryService { rpc GetUser (GetUserQuery) returns (UserDto); } message CreateUserCommand { string name = 1; string email = 2; } message CreateUserResponse { int32 user_id = 1; } message DeleteUserCommand { int32 user_id = 1; } message GetUserQuery { int32 user_id = 1; } message UserDto { int32 id = 1; string name = 2; string email = 3; } ``` **2. Configure services:** ```csharp var builder = WebApplication.CreateBuilder(args); // Register CQRS services builder.Services.AddSvrntyCQRS(); builder.Services.AddDefaultCommandDiscovery(); builder.Services.AddDefaultQueryDiscovery(); // Register commands and queries builder.Services.AddCommand(); builder.Services.AddCommand(); builder.Services.AddQuery(); // Add gRPC builder.Services.AddGrpc(); var app = builder.Build(); // Map auto-generated service implementations app.MapGrpcService(); app.MapGrpcService(); // Enable reflection for tools app.MapGrpcReflectionService(); app.Run(); ``` **3. Source generator automatically creates:** - `CommandServiceImpl` class implementing `CommandService.CommandServiceBase` - `QueryServiceImpl` class implementing `QueryService.QueryServiceBase` ## How It Works ``` ┌─────────────────────────────┐ │ Build Time │ ├─────────────────────────────┤ │ 1. Read .proto files │ │ 2. Discover commands/queries│ │ 3. Generate service impls │ │ 4. Compile into assembly │ └─────────────────────────────┘ │ ▼ ┌─────────────────────────────┐ │ Runtime │ ├─────────────────────────────┤ │ gRPC Request │ │ → Deserialize protobuf │ │ → Validate │ │ → Authorize │ │ → Execute handler │ │ → Serialize response │ └─────────────────────────────┘ ``` ## Commands via gRPC ### Command Without Result ```csharp public record DeleteUserCommand { public int UserId { get; init; } } public class DeleteUserCommandHandler : ICommandHandler { public async Task HandleAsync(DeleteUserCommand command, CancellationToken cancellationToken) { // Delete user logic } } ``` **.proto definition:** ```protobuf service CommandService { rpc DeleteUser (DeleteUserCommand) returns (google.protobuf.Empty); } message DeleteUserCommand { int32 user_id = 1; } ``` **gRPC Client:** ```csharp var client = new CommandService.CommandServiceClient(channel); var request = new DeleteUserCommand { UserId = 123 }; await client.DeleteUserAsync(request); ``` ### Command With Result ```csharp public record CreateUserCommand { public string Name { get; init; } = string.Empty; public string Email { get; init; } = string.Empty; } public class CreateUserCommandHandler : ICommandHandler { public async Task HandleAsync(CreateUserCommand command, CancellationToken cancellationToken) { // Create user and return ID return newUserId; } } ``` **.proto definition:** ```protobuf service CommandService { rpc CreateUser (CreateUserCommand) returns (CreateUserResponse); } message CreateUserCommand { string name = 1; string email = 2; } message CreateUserResponse { int32 user_id = 1; } ``` **gRPC Client:** ```csharp var client = new CommandService.CommandServiceClient(channel); var request = new CreateUserCommand { Name = "John Doe", Email = "john@example.com" }; var response = await client.CreateUserAsync(request); var userId = response.UserId; ``` ## Queries via gRPC ```csharp public record GetUserQuery { public int UserId { get; init; } } public record UserDto { public int Id { get; init; } public string Name { get; init; } = string.Empty; public string Email { get; init; } = string.Empty; } public class GetUserQueryHandler : IQueryHandler { public async Task HandleAsync(GetUserQuery query, CancellationToken cancellationToken) { // Fetch and return user } } ``` **.proto definition:** ```protobuf service QueryService { rpc GetUser (GetUserQuery) returns (UserDto); } message GetUserQuery { int32 user_id = 1; } message UserDto { int32 id = 1; string name = 2; string email = 3; } ``` **gRPC Client:** ```csharp var client = new QueryService.QueryServiceClient(channel); var request = new GetUserQuery { UserId = 123 }; var user = await client.GetUserAsync(request); ``` ## Validation ### Automatic Validation with Rich Error Model ```csharp public class CreateUserCommandValidator : AbstractValidator { public CreateUserCommandValidator() { RuleFor(x => x.Name) .NotEmpty() .WithMessage("Name is required"); RuleFor(x => x.Email) .EmailAddress() .WithMessage("Valid email address is required"); } } ``` **Validation failure response:** ```protobuf google.rpc.Status { code: 3 // INVALID_ARGUMENT message: "Validation failed" details: [ google.rpc.BadRequest { field_violations: [ { field: "name", description: "Name is required" }, { field: "email", description: "Valid email address is required" } ] } ] } ``` **Client handling:** ```csharp using Grpc.Core; using Google.Rpc; try { var response = await client.CreateUserAsync(request); } catch (RpcException ex) when (ex.StatusCode == StatusCode.InvalidArgument) { var status = ex.GetRpcStatus(); var badRequest = status.GetDetail(); foreach (var violation in badRequest.FieldViolations) { Console.WriteLine($"{violation.Field}: {violation.Description}"); } } ``` ## Performance Benefits ### Binary Protocol gRPC uses Protocol Buffers (binary format) instead of JSON: **JSON (HTTP):** ```json { "id": 123, "name": "John Doe", "email": "john@example.com" } ``` **Size:** ~71 bytes **Protobuf (gRPC):** ``` Binary representation ``` **Size:** ~35 bytes **Result:** ~50% smaller payload ### HTTP/2 Multiplexing - Multiple requests over single connection - Header compression - Server push capability - Bidirectional streaming ## gRPC vs HTTP Comparison | Feature | gRPC | HTTP (Minimal API) | |---------|------|-------------------| | Protocol | HTTP/2 | HTTP/1.1 or HTTP/2 | | Format | Protobuf (binary) | JSON (text) | | Performance | Very fast | Fast | | Payload Size | Small | Larger | | Browser Support | Limited (grpc-web) | Full | | Tooling | grpcurl, Postman | curl, Postman, Swagger | | Streaming | Native bidirectional | Server-Sent Events | | Code Generation | Automatic | Automatic | | Type Safety | Strong | Strong | ### When to Use gRPC ✅ **Use gRPC for:** - Microservices communication - High-performance APIs - Real-time bidirectional streaming - Internal APIs - Polyglot environments ### When to Use HTTP ✅ **Use HTTP for:** - Public APIs - Browser-based clients - Simple REST APIs - Legacy system integration - Human-readable debugging ### Dual Protocol **Best of both worlds:** ```csharp // Same handlers, multiple protocols builder.Services.AddCommand(); // HTTP endpoints app.MapSvrntyCommands(); // gRPC endpoints app.MapGrpcService(); ``` Clients choose their preferred protocol! ## Documentation ### [Getting Started](getting-started-grpc.md) First gRPC service: - Installation - .proto file creation - Service registration - Testing with grpcurl ### [Proto File Setup](proto-file-setup.md) .proto file creation: - Syntax and conventions - Message definitions - Service definitions - Importing common types ### [Source Generators](source-generators.md) How code generation works: - Build-time generation - Generated code structure - Customization options - Troubleshooting ### [Service Implementation](service-implementation.md) Generated service implementations: - CommandServiceImpl - QueryServiceImpl - Validation integration - Authorization integration ### [gRPC Reflection](grpc-reflection.md) gRPC reflection for tools: - Enabling reflection - Using grpcurl - Postman support - Service discovery ### [gRPC Clients](grpc-clients.md) Consuming gRPC services: - C# client - TypeScript client - Go client - Python client ### [gRPC Troubleshooting](grpc-troubleshooting.md) Common issues: - Connection errors - Validation errors - Code generation issues - Performance tuning ## Best Practices ### ✅ DO - Use gRPC for microservices - Define clear .proto contracts - Use gRPC reflection in development - Handle RpcException properly - Version your services - Use deadlines/timeouts - Enable compression ### ❌ DON'T - Don't skip error handling - Don't expose gRPC publicly without security - Don't ignore validation - Don't use gRPC for browser apps without grpc-web - Don't forget cancellation tokens ## What's Next? - **[Getting Started](getting-started-grpc.md)** - Create your first gRPC service - **[Proto File Setup](proto-file-setup.md)** - Learn .proto file conventions - **[Source Generators](source-generators.md)** - Understand code generation - **[Service Implementation](service-implementation.md)** - Explore generated code - **[gRPC Clients](grpc-clients.md)** - Build gRPC clients ## See Also - [Commands Overview](../core-features/commands/README.md) - [Queries Overview](../core-features/queries/README.md) - [Validation Overview](../core-features/validation/README.md) - [HTTP Integration](../http-integration/README.md) - [Getting Started: Choosing HTTP or gRPC](../getting-started/06-choosing-http-or-grpc.md)