How to Use Connect-go (Connect Protocol) as a gRPC Alternative

Web
Connect-go is a lightweight, HTTP/2-based RPC framework that offers a simpler, more web-friendly alternative to gRPC by using standard HTTP/2 streaming and JSON/Protobuf encoding without requiring the complex gRPC wire format or metadata handling.

Connect-go is a lightweight, HTTP/2-based RPC framework that offers a simpler, more web-friendly alternative to gRPC by using standard HTTP/2 streaming and JSON/Protobuf encoding without requiring the complex gRPC wire format or metadata handling. You can drop it into existing Go projects to get gRPC-like code generation and streaming capabilities while maintaining compatibility with standard web servers, browsers, and proxies that often block raw gRPC traffic.

To get started, you first need the Connect protocol compiler plugin to generate Go code from your .proto files. Run the following command to install the necessary tools and generate the client and server interfaces:

# Install the Connect protocol compiler plugin
go install github.com/bufbuild/connect-go/cmd/protoc-gen-connect-go@latest

# Generate Go code from your proto definitions
protoc --go_out=. --go_opt=paths=source_relative \
       --connect-go_out=. --connect-go_opt=paths=source_relative \
       path/to/your/service.proto

Once generated, implementing a server is straightforward and mirrors standard Go HTTP handlers. You define your service logic and register it with the Connect mux, which handles the HTTP/2 framing automatically:

package main

import (
    "context"
    "log"
    "net/http"

    connect "github.com/bufbuild/connect-go"
    "github.com/example/myproject/gen/connect" // Your generated package
)

type GreeterService struct {
    connect.UnimplementedGreeterHandler
}

func (s *GreeterService) SayHello(ctx context.Context, req *connect.Request[connect.HelloRequest]) (*connect.Response[connect.HelloResponse], error) {
    return connect.NewResponse(&connect.HelloResponse{
        Message: "Hello, " + req.Msg.Name + "!",
    }), nil
}

func main() {
    mux := http.NewServeMux()
    mux.Handle(connect.NewHandler(greeterConnect.NewGreeterHandler(&GreeterService{})))
    
    log.Println("Server listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", mux))
}

On the client side, you instantiate a client using the generated interface, which supports unary calls, server streaming, client streaming, and bidirectional streaming out of the box. Connect-go handles retries, timeouts, and error mapping automatically:

client := greeterConnect.NewGreeterClient(
    http.DefaultClient,
    "http://localhost:8080",
)

resp, err := client.SayHello(context.Background(), connect.NewRequest(&connect.HelloRequest{
    Name: "Alice",
}))
if err != nil {
    log.Fatalf("call failed: %v", err)
}
log.Println(resp.Msg.Message)

The primary advantage over gRPC is that Connect uses standard HTTP/2 with JSON or Protobuf payloads, making it easier to debug with tools like curl or browser DevTools and ensuring it works seamlessly behind load balancers and CDNs that don't support raw gRPC. It also provides a cleaner Go API that avoids the boilerplate often associated with the official gRPC-Go library.