Exploring the Power of gRPC-Gateway for Writing RESTful Services

30th June 2026

Rajiv Ranjan Singh

Agenda

2

Speaker - Rajiv Ranjan Singh

3

What is gRPC-Gateway

4

How gRPC-Gateway works

  1. Client sends HTTP/JSON request
  2. gRPC-Gateway proxy receives request
  3. Proxy translates to gRPC call
  4. gRPC service processes request
  5. Response flows back through proxy
  6. Client receives HTTP/JSON response
5

How gRPC-Gateway works

6

Ways to do gRPC Gateway HTTP Mapping

7

Method 1: Inline Annotations

8

Method 2: External gRPC API Configuration (YAML File)

type: google.api.Service
config_version: 3

http:
  rules:
    - selector: hello.v1.GreeterService.SayHello
      post: /v1/hello
      body: "*"
9

Method 3: Unannotated Methods (Auto-generate)

10

Method 4: Multiple HTTP Bindings (Advanced)

11

How to write simple hello world service using gRPC-Gateway

12

Step 1: Define the Service (proto/hello.proto)

13

Step 2: Configure buf (buf.yaml)

version: v2
modules:
  - path: proto
    name: buf.build/wearedevelopers-world-congress-europe-2026/hello
deps:
  - buf.build/googleapis/googleapis
lint:
  use:
    - STANDARD
    - FILE_LOWER_SNAKE_CASE
  ignore:
    # Ignore the response naming convention for streaming RPCs
    - RPC_RESPONSE_STANDARD_NAME
14

Step 3: Configure Code Generation (buf.gen.yaml)

version: v2
managed:
  enabled: true
  disable:
    - module: buf.build/googleapis/googleapis
  override:
    - file_option: go_package_prefix
      value: github.com/iamrajiv/wearedevelopers-world-congress-europe-2026/examples/hello/gen/proto
plugins:
  - remote: buf.build/protocolbuffers/go:v1.36.11
    out: gen/proto
    opt:
      - paths=source_relative
  - remote: buf.build/grpc/go:v1.5.1
    out: gen/proto
    opt:
      - paths=source_relative
  - remote: buf.build/grpc-ecosystem/gateway:v2.29.0
    out: gen/proto
    opt:
      - paths=source_relative
15

Step 4: Implement the Server (main.go)

type server struct {
    hellopb.UnimplementedGreeterServiceServer
}
16

Step 5: Start gRPC Server

func runGRPCServer() error {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        return fmt.Errorf("failed to listen: %v", err)
    }

    grpcServer := grpc.NewServer()
    hellopb.RegisterGreeterServiceServer(grpcServer, &server{})

    // Register reflection service for grpcurl
    reflection.Register(grpcServer)

    log.Println("gRPC server listening on :50051")
    if err := grpcServer.Serve(lis); err != nil {
        return fmt.Errorf("failed to serve gRPC: %v", err)
    }
    return nil
}
17

Step 6: Start REST Gateway

func runRESTGateway() error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()

    // Create gRPC-Gateway mux
    mux := runtime.NewServeMux()

    // Register the service handler
    opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
    err := hellopb.RegisterGreeterServiceHandlerFromEndpoint(ctx, mux, "localhost:50051", opts)
    if err != nil {
        return fmt.Errorf("failed to register gateway: %v", err)
    }

    // Start HTTP server
    log.Println("gRPC-Gateway (REST) server listening on :8080")
    if err := http.ListenAndServe(":8080", mux); err != nil {
        return fmt.Errorf("failed to serve REST: %v", err)
    }
    return nil
}
18

Testing the Service

gRPC Client Test:

grpcurl -plaintext \
  -d '{"name": "WeAreDevelopers"}' localhost:50051 hello.v1.GreeterService/SayHello

REST Client Test:

curl -X POST http://localhost:8080/v1/hello \
  -H "Content-Type: application/json" -d '{"name": "WeAreDevelopers"}'

Both Return:

{
  "message": "Hello, WeAreDevelopers!"
}
19

Advanced features gRPC-Gateway provides

20

Advanced features gRPC-Gateway provides - Custom HTTP Mapping

21

Advanced features gRPC-Gateway provides - Streaming Support

service GreeterService {
  rpc StreamGreetings(StreamRequest) returns (stream HelloResponse) {
    option (google.api.http) = {
      get: "/v1/greetings/stream"
    };
  }
}

Returns: NDJSON (newline-delimited JSON) streaming over HTTP using chunked transfer encoding

Streaming Support:

22

Advanced features gRPC-Gateway provides - Error Handling

func (s *server) GetUser(ctx context.Context, req *GetUserRequest) (*User, error) {
    // Simulate database lookup
    user, err := s.db.QueryRowContext(ctx, "SELECT user_id, name, email, created_at FROM users WHERE user_id = ?", req.UserId).Scan()

    // Handle not found error
    if err == sql.ErrNoRows {
        return nil, status.Errorf(codes.NotFound, "user %s not found", req.UserId)
    }

    // Handle database errors
    if err != nil {
        return nil, status.Errorf(codes.Internal, "database error: %v", err)
    }

    // Validate user data
    if user == nil {
        return nil, status.Error(codes.InvalidArgument, "invalid user data")
    }

    return user, nil
}
23

Advanced features gRPC-Gateway provides - Error Handling

Translation:

24

Key Takeaways

25

References

26

Thank you

Rajiv Ranjan Singh

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)