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...