TechSetupGuides
Advancedgrpcgorpchttp2microservices

gRPC-Go: HTTP/2 RPC Framework

Use gRPC-Go to build high-performance RPC services with HTTP/2, code generation, and streaming support.

  1. Step 1

    Check Go version

    gRPC-Go requires one of the two latest major Go releases (Go 1.20 or higher). Check your Go version:

    go version
  2. Step 2

    Create a new Go module

    Initialize a new Go module for your gRPC project:

    mkdir grpc-example
    cd grpc-example
    go mod init grpc-example
  3. Step 3

    Install gRPC-Go dependency

    Add the gRPC-Go library to your project. Go modules will automatically fetch dependencies when you build or run your code:

    import "google.golang.org/grpc"
  4. Step 4

    Install Protocol Buffers compiler

    gRPC uses Protocol Buffers (protobuf) for defining service interfaces. Install the protobuf compiler (protoc):

    # On macOS:
    brew install protobuf
    
    # On Ubuntu/Debian:
    sudo apt-get install protobuf-compiler
    
    # On Arch Linux:
    sudo pacman -S protobuf
    
    # Verify installation:
    protoc --version
  5. Step 5

    Install Go Protocol Buffers plugins

    Install necessary tools to generate Go code from protobuf definitions:

    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
  6. Step 6

    Define your service in protobuf

    Create a .proto file that defines your service interface and message types. This is the contract between client and server:

    syntax = "proto3";
    
    package example;
    option go_package = "grpc-example/pb";
    
    service Greeter {
      rpc SayHello (HelloRequest) returns (HelloResponse);
      rpc SayHelloServerStream (HelloRequest) returns (stream HelloResponse);
      rpc SayHelloClientStream (stream HelloRequest) returns (HelloResponse);
      rpc SayHelloBidirectionalStream (stream HelloRequest) returns (stream HelloResponse);
    }
    
    message HelloRequest {
      string name = 1;
    }
    
    message HelloResponse {
      string greeting = 1;
    }
  7. Step 7

    Generate Go code from protobuf

    Use protoc to generate Go files from your .proto definition:

    mkdir -p pb
    protoc --go_out=. --go_opt=paths=source_relative \
      --go-grpc_out=. --go-grpc_opt=paths=source_relative \
      pb/hello.proto
  8. Step 8

    Implement the gRPC server

    Create a server that implements the service defined in your .proto file. The generated Go code provides interfaces you need to implement:

    package main
    
    import (
    	"context"
    	"fmt"
    	"io"
    	"log"
    	"net"
    
    	pb "grpc-example/pb"
    	"google.golang.org/grpc"
    )
    
    type server struct {
    	pb.UnimplementedGreeterServer
    }
    
    func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
    	return &pb.HelloResponse{
    		Greeting: fmt.Sprintf("Hello, %s!", req.Name),
    	}, nil
    }
    
    func (s *server) SayHelloServerStream(req *pb.HelloRequest, stream pb.Greeter_SayHelloServerStreamServer) error {
    	for i := 0; i < 5; i++ {
    		err := stream.Send(&pb.HelloResponse{
    			Greeting: fmt.Sprintf("Hello, %s! Message %d", req.Name, i+1),
    		})
    		if err != nil {
    			return err
    		}
    	}
    	return nil
    }
    
    func (s *server) SayHelloBidirectionalStream(stream pb.Greeter_SayHelloBidirectionalStreamServer) error {
    	for {
    		in, err := stream.Recv()
    		if err == io.EOF {
    			return nil
    		}
    		if err != nil {
    			return err
    		}
    		if err := stream.Send(&pb.HelloResponse{
    			Greeting: fmt.Sprintf("Echo: Hello, %s!", in.Name),
    		}); err != nil {
    			return err
    		}
    	}
    }
    
    func main() {
    	lis, err := net.Listen("tcp", ":50051")
    	if err != nil {
    		log.Fatalf("failed to listen: %v", err)
    	}
    
    	grpcServer := grpc.NewServer()
    	pb.RegisterGreeterServer(grpcServer, &server{})
    
    	log.Printf("Server starting on port 50051")
    	if err := grpcServer.Serve(lis); err != nil {
    		log.Fatalf("failed to serve: %v", err)
    	}
    }
  9. Step 9

    Create a gRPC client

    Implement a client that connects to your gRPC server and makes RPC calls:

    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"time"
    
    	pb "grpc-example/pb"
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/credentials/insecure"
    )
    
    func main() {
    	conn, err := grpc.NewClient(
    		"localhost:50051",
    		grpc.WithTransportCredentials(insecure.NewCredentials()),
    	)
    	if err != nil {
    		log.Fatalf("failed to connect: %v", err)
    	}
    	defer conn.Close()
    
    	client := pb.NewGreeterClient(conn)
    
    	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    	resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: "World"})
    	cancel()
    	if err != nil {
    		log.Fatalf("error when calling SayHello: %v", err)
    	}
    	fmt.Println(resp.Greeting)
    }
  10. Step 10

    Use server streaming

    Server streaming allows the server to send multiple responses to a single client request:

    import "io"
    
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    stream, err := client.SayHelloServerStream(ctx, &pb.HelloRequest{Name: "World"})
    cancel()
    if err != nil {
    	log.Fatalf("error when calling SayHelloServerStream: %v", err)
    }
    
    for {
    	resp, err := stream.Recv()
    	if err == io.EOF {
    		break
    	}
    	if err != nil {
    		log.Fatalf("error while receiving: %v", err)
    	}
    	fmt.Println(resp.Greeting)
    }
  11. Step 11

    Configure TLS encryption

    gRPC uses TLS for secure communication in production. Generate self-signed certificates for development:

    # Generate root CA private key
    openssl genrsa -out ca.key 4096
    
    # Generate root CA certificate
    openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt -subj "/CN=MyCA"
    
    # Generate server private key and certificate
    openssl genrsa -out server.key 4096
    openssl req -new -key server.key -out server.csr -subj "/CN=localhost"
    openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256
    
    # Generate client certificate
    openssl genrsa -out client.key 4096
    openssl req -new -key client.key -out client.csr -subj "/CN=client"
    openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365 -sha256
    ⚠ Heads up: Store your private keys securely. Never commit them to version control. For production, use certificates from trusted CAs.
  12. Step 12

    Use TLS in server and client

    Configure both server and client to use TLS certificates for secure communication:

    import (
    	"crypto/tls"
    	"crypto/x509"
    	"io/ioutil"
    	"google.golang.org/grpc/credentials"
    )
    
    // Server-side TLS
    func createServerTLS() credentials.TransportCredentials {
    	cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
    	if err != nil {
    		log.Fatalf("%v", err)
    	}
    	
    	caCert, err := ioutil.ReadFile("ca.crt")
    	if err != nil {
    		log.Fatalf("%v", err)
    	}
    	caCertPool := x509.NewCertPool()
    	caCertPool.AppendCertsFromPEM(caCert)
    	
    	return credentials.NewTLS(&tls.Config{
    		Certificates: []tls.Certificate{cert},
    		ClientAuth:   tls.RequireAndVerifyClientCert,
    		ClientCAs:    caCertPool,
    	})
    }
    
    grpcServer := grpc.NewServer(grpc.Creds(createServerTLS()))
    
    // Client-side TLS
    func createClientTLS() credentials.TransportCredentials {
    	cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
    	if err != nil {
    		log.Fatalf("%v", err)
    	}
    	
    	caCert, err := ioutil.ReadFile("ca.crt")
    	if err != nil {
    		log.Fatalf("%v", err)
    	}
    	caCertPool := x509.NewCertPool()
    	caCertPool.AppendCertsFromPEM(caCert)
    	
    	return credentials.NewTLS(&tls.Config{
    		Certificates: []tls.Certificate{cert},
    		RootCAs:      caCertPool,
    		ServerName:   "localhost",
    	})
    }
    
    conn, err := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(createClientTLS()))
  13. Step 13

    Add metadata interceptors

    Use interceptors to add metadata (headers) to requests and responses for authentication, logging, and other cross-cutting concerns:

    import (
    	"context"
    	"google.golang.org/grpc/metadata"
    )
    
    // Server-side unary interceptor to log metadata
    func unaryServerInterceptor(ctx context.Context, req interface{}, 
        info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    	md, ok := metadata.FromIncomingContext(ctx)
    	if ok {
    		authToken := md.Get("authorization")
    		log.Printf("Auth token received: %v", authToken)
    	}
    	return handler(ctx, req)
    }
    
    grpcServer := grpc.NewServer(grpc.UnaryInterceptor(unaryServerInterceptor))
    
    // Client request with metadata
    ctx := metadata.NewOutgoingContext(context.Background(), 
        metadata.Pairs("authorization", "Bearer token123"))
    resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: "World"})
  14. Step 14

    Implement health checking

    gRPC provides built-in health checking service for monitoring and load balancing:

    import (
    	"google.golang.org/grpc/health"
    	"google.golang.org/grpc/health/grpc_health_v1"
    )
    
    func main() {
    	lis, err := net.Listen("tcp", ":50051")
    	if err != nil {
    		log.Fatalf("failed to listen: %v", err)
    	}
    
    	grpcServer := grpc.NewServer()
    	pb.RegisterGreeterServer(grpcServer, &server{})
    	
    	// Register health server
    	healthServer := health.NewServer()
    	healthServer.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING)
    	healthServer.SetServingStatus("Greeter", grpc_health_v1.HealthCheckResponse_SERVING)
    	grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)
    	
    	if err := grpcServer.Serve(lis); err != nil {
    		log.Fatalf("failed to serve: %v", err)
    	}
    }
    
    // Health check client
    healthClient := grpc_health_v1.NewHealthClient(conn)
    resp, err := healthClient.Check(ctx, &grpc_health_v1.HealthCheckRequest{Service: "Greeter"})
    fmt.Printf("Health status: %v\n", resp.Status)
  15. Step 15

    Configure keepalive

    Keepalive settings help maintain connections and detect dead peers in long-running services:

    import (
    	"time"
    	"google.golang.org/grpc/keepalive"
    )
    
    // Server keepalive configuration
    grpcServer := grpc.NewServer(
    	grpc.KeepaliveParams(keepalive.ServerParameters{
    		Time:                10 * time.Second,
    		Timeout:             3 * time.Second,
    		PermitWithoutStream: true,
    	}),
    )
    
    // Client keepalive configuration
    conn, err := grpc.NewClient("localhost:50051",
    	grpc.WithKeepaliveParams(keepalive.ClientParameters{
    		Time:                10 * time.Second,
    		Timeout:             3 * time.Second,
    		PermitWithoutStream: true,
    	}),
    )
  16. Step 16

    Deploy with Docker

    Containerize your gRPC service for easy deployment and scaling:

    FROM golang:1.21-alpine AS builder
    
    WORKDIR /app
    COPY go.mod go.sum ./
    RUN go mod download
    COPY . .
    RUN go build -o server ./server.go
    
    FROM alpine:latest
    RUN apk --no-cache add ca-certificates
    WORKDIR /root/
    COPY --from=builder /app/server .
    COPY --from=builder /app/server.crt /app/server.key /app/ca.crt .
    
    EXPOSE 50051
    CMD ["./server"]
  17. Step 17

    Enable gRPC logging

    Enable verbose logging for debugging gRPC internals:

    # Enable gRPC logging
    export GRPC_GO_LOG_VERBOSITY_LEVEL=99
    export GRPC_GO_LOG_SEVERITY_LEVEL=info
    
    # Run your server and see detailed logs
    # Logs include connection details, stream state, and error traces
  18. Step 18

    Explore gRPC-Go examples

    The gRPC-Go repository contains many examples demonstrating additional features like OAuth2 authentication, name resolution, and more at the examples/ directory:

    # Clone the gRPC-Go repository to explore examples
    git clone https://github.com/grpc/grpc-go
    cd grpc-go/examples
    
    # Available examples:
    # - features/authentication - OAuth2 authentication
    # - features/name_resolving - DNS service discovery
    # - features/cancellation - Request cancellation
    # - features/compression - Message compression
    # - features/deadline - Request deadlines
    # - features/error_details - Detailed error handling

Feature requests

Sign in to suggest features or vote on existing ones.

No feature requests yet.

Discussion

0 people marked this as worked·Sign in to mark your own.

Sign in to join the discussion.

No comments yet.

gRPC-Go: HTTP/2 RPC Framework Setup Guide — TechSetupGuides