Golang / GoLang System Architecture and Testing Interview Questions
How do you implement a gRPC server in Go, including error handling and interceptors?
Implementing a gRPC server follows a code-generation-first workflow: define the proto, generate Go stubs, implement the interface, and start the server. Interceptors (gRPC's equivalent of HTTP middleware) add cross-cutting concerns like logging and auth.
// Step 1: implement the generated server interface type userServiceServer struct { pb.UnimplementedUserServiceServer // embed for forward compatibility repo UserRepository log *slog.Logger } func (s *userServiceServer) GetUser( ctx context.Context, req *pb.GetUserRequest, ) (*pb.User, error) { if req.Id <= 0 { return nil, status.Errorf(codes.InvalidArgument, "id must be positive, got %d", req.Id) } user, err := s.repo.FindByID(ctx, int(req.Id)) if err != nil { if errors.Is(err, ErrNotFound) { return nil, status.Errorf(codes.NotFound, "user %d not found", req.Id) } s.log.Error("repo error", "err", err) return nil, status.Errorf(codes.Internal, "internal error") } return &pb.User{Id: int64(user.ID), Name: user.Name, Email: user.Email}, nil } // Interceptor (middleware equivalent) func loggingInterceptor(log *slog.Logger) grpc.UnaryServerInterceptor { return func( ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (any, error) { start := time.Now() resp, err := handler(ctx, req) log.Info("RPC", "method", info.FullMethod, "duration", time.Since(start), "error", err, ) return resp, err } } // Step 2: start the server func main() { lis, _ := net.Listen("tcp", ":9090") srv := grpc.NewServer( grpc.ChainUnaryInterceptor( loggingInterceptor(log), recoveryInterceptor(), authInterceptor(secret), ), ) pb.RegisterUserServiceServer(srv, &userServiceServer{repo: repo}) reflection.Register(srv) // enables grpcurl inspection srv.Serve(lis) }
gRPC status codes: always return structured status errors using status.Errorf(codes.X, ...). Clients receive the code and message and can handle them programmatically. The mapping to HTTP status codes is standardised (NotFoundβ404, InvalidArgumentβ400, Internalβ500).
More Related questions...