Golang / GoLang System Architecture and Testing Interview Questions
How do you version gRPC APIs in Go without breaking existing clients?
Breaking changes in gRPC are harder to recover from than REST — generated client code must be recompiled. The Protobuf wire format and Go's embedded Unimplemented* pattern provide the tools to evolve APIs safely.
// Protobuf field number rules (never change): // - Field numbers 1-15: used for frequently-sent fields (1-byte encoded) // - Never reuse a field number â remove fields by reserving them // - Never rename fields if using JSON encoding // Safe changes (backward compatible): // 1. Add new optional fields with new field numbers // 2. Add new RPC methods to the service // 3. Add values to enums (with care) // Breaking changes (require new major version): // 1. Remove or rename fields // 2. Change field types // 3. Remove RPC methods // In user.proto â safe evolution: message User { int64 id = 1; string name = 2; string email = 3; // Added in v1.1 â old clients ignore this field string avatar_url = 4; // Removed field: reserved to prevent accidental reuse reserved 5; reserved "phone_number"; } // Major version bump when breaking changes required // package user.v2; // â separate proto package, separate Go package // â clients opt-in by importing v2 // Server supporting both v1 and v2 simultaneously func main() { grpcServer := grpc.NewServer() v1pb.RegisterUserServiceServer(grpcServer, &v1Handler{}) v2pb.RegisterUserServiceServer(grpcServer, &v2Handler{}) // gRPC uses fully qualified service name to route: // user.v1.UserService vs user.v2.UserService }
Field reservation: when you remove a field, add its number and name to reserved. This prevents future schema changes from accidentally reusing the old field number and silently corrupting old clients that still send the deprecated field.
More Related questions...