From Legacy Rest to GPC - Vanguard-Go ⚔️
So what is Vanguard? Vanguard is a powerful library for Go net/http servers that enables seamless transcoding between REST and RPC protocols. Whether you need to bridge the gap between gRPC, gRPC-Web, Connect, or REST, Vanguard has got you covered. With support for Google's HTTP transcoding options, it can effortlessly translate protocols using strongly typed Protobuf definitions. Why Vanguard? Vanguard offers a range of compelling use cases that make it an invaluable addition to your services: RESTful Transformation: By leveraging HTTP transcoding annotations, you can effortlessly support REST clients. This feature is especially handy during the migration from a REST API to a schema-driven RPC API. With the right annotations, your existing REST clients can seamlessly access your API, even as you transition your server implementations to Protobuf and RPC. Efficiency and Code Generation: Unlike traditional approaches like gRPC-Gateway, Vanguard operates efficiently within Go servers, compatible with various servers such as Connect and gRPC. It doesn't rely on extensive code generation, eliminating the need for additional code generation steps. This flexibility ensures that your code can adapt dynamically, loading service definitions from configuration, schema registries, or via gRPC Server Reflection, making it a perfect fit for proxies without the hassle of recompilation and redeployment each time an RPC service schema changes. Legacy Compatibility: The HTTP transcoding annotations also empower you to support legacy REST API servers when clients are accustomed to using Protobuf RPC. This lets you embrace RPC in specific teams, such as for web or mobile clients, without the prerequisite of migrating all backend API services. Seamless Protocol Bridging: If your organization is transitioning from gRPC to Connect, Vanguard acts as a bridge between the protocols. This facilitates the use of your existing gRPC service handlers with Connect clients, allowing you to smoothly adapt to Connect's enhanced usability and inspectability with web browsers and mobile devices. No need to overhaul your server handler logic before migrating clients to Connect. To bridge a REST API to gRPC using the Vanguard library in Go, as provided by connectrpc/vanguard-go, you can leverage its ability to transcode between REST and RPC protocols seamlessly. This guide outlines the steps to set up a server that supports both REST and gRPC clients using Vanguard, based on the library’s capabilities described in the repository. Prerequisites Go: Ensure Go is installed (version compatible with the two most recent major releases, per the library’s support). Protobuf: Install protoc and the necessary plugins (protoc-gen-go, protoc-gen-connect-go, protoc-gen-grpc-go). Vanguard: Install the Vanguard library: go get connectrpc.com/vanguard Step-by-Step Guide 1. Define Your Protobuf Schema Create a .proto file to define your service and messages. Include Google’s HTTP transcoding annotations to map gRPC methods to RESTful endpoints. For example: syntax = "proto3"; package example.v1; import "google/api/annotations.proto"; service ExampleService { rpc GetItem(GetItemRequest) returns (Item) { option (google.api.http) = { get: "/v1/items/{id}" }; } rpc CreateItem(CreateItemRequest) returns (Item) { option (google.api.http) = { post: "/v1/items" body: "*" }; } } message GetItemRequest { string id = 1; } message CreateItemRequest { string name = 1; } message Item { string id = 1; string name = 2; } The (google.api.http) annotations map gRPC methods to REST paths and HTTP methods. Save this as example.proto in a directory like proto/. 2. Generate Code Compile the .proto file to generate Go code for gRPC, Connect, and REST handling: protoc --go_out=. --go_opt=paths=source_relative \ --connect-go_out=. --connect-go_opt=paths=source_relative \ --grpc-go_out=. --grpc-go_opt=paths=source_relative \ proto/example.proto This generates: gRPC service definitions. Connect handlers for HTTP/1.1 compatibility. Structs for messages. 3. Implement the Service Create a Go server that implements the gRPC service. For example: package main import ( "context" "log" "net/http" examplev1 "path/to/generated/example/v1" "connectrpc.com/connect" ) type ExampleServer struct { examplev1connect.UnimplementedExampleServiceHandler } func (s *ExampleServer) GetItem(ctx context.Context, req *connect.Request[examplev1.GetItemRequest]) (*connect.Response[examplev1.Item], error) { // Fetch item logic (e.g., from a database). item := &examplev1.Item{Id: req.Msg.Id, Name: "Sample Item"} return connect.NewResponse(item), nil } func (s *ExampleServer) CreateItem(ctx context.Context, req *connect.Request[examplev1.CreateItemRequest]) (*connec

So what is Vanguard?
Vanguard is a powerful library for Go net/http servers that enables seamless transcoding between REST and RPC protocols. Whether you need to bridge the gap between gRPC, gRPC-Web, Connect, or REST, Vanguard has got you covered. With support for Google's HTTP transcoding options, it can effortlessly translate protocols using strongly typed Protobuf definitions.
Why Vanguard?
Vanguard offers a range of compelling use cases that make it an invaluable addition
to your services:
RESTful Transformation: By leveraging HTTP transcoding annotations, you can effortlessly
support REST clients. This feature is especially handy during the migration from a REST API
to a schema-driven RPC API. With the right annotations, your existing REST clients can
seamlessly access your API, even as you transition your server implementations to Protobuf
and RPC.Efficiency and Code Generation: Unlike traditional approaches like gRPC-Gateway,
Vanguard operates efficiently within Go servers, compatible with various servers such as
Connect and gRPC.
It doesn't rely on extensive code generation, eliminating the need for additional code
generation steps. This flexibility ensures that your code can adapt dynamically, loading
service definitions from configuration, schema registries, or via
gRPC Server Reflection,
making it a perfect fit for proxies without the hassle of recompilation and redeployment
each time an RPC service schema changes.Legacy Compatibility: The HTTP transcoding annotations also empower you to support
legacy REST API servers when clients are accustomed to using Protobuf RPC. This lets
you embrace RPC in specific teams, such as for web or mobile clients, without the
prerequisite of migrating all backend API services.Seamless Protocol Bridging: If your organization is transitioning from gRPC to Connect,
Vanguard acts as a bridge between the protocols. This facilitates the use of your existing
gRPC service handlers with Connect clients, allowing you to smoothly adapt to Connect's
enhanced usability and inspectability with web browsers and mobile devices. No need to
overhaul your server handler logic before migrating clients to Connect.
To bridge a REST API to gRPC using the Vanguard library in Go, as provided by connectrpc/vanguard-go
, you can leverage its ability to transcode between REST and RPC protocols seamlessly. This guide outlines the steps to set up a server that supports both REST and gRPC clients using Vanguard, based on the library’s capabilities described in the repository.
Prerequisites
- Go: Ensure Go is installed (version compatible with the two most recent major releases, per the library’s support).
-
Protobuf: Install
protoc
and the necessary plugins (protoc-gen-go
,protoc-gen-connect-go
,protoc-gen-grpc-go
). - Vanguard: Install the Vanguard library:
go get connectrpc.com/vanguard
Step-by-Step Guide
1. Define Your Protobuf Schema
Create a .proto
file to define your service and messages. Include Google’s HTTP transcoding annotations to map gRPC methods to RESTful endpoints. For example:
syntax = "proto3";
package example.v1;
import "google/api/annotations.proto";
service ExampleService {
rpc GetItem(GetItemRequest) returns (Item) {
option (google.api.http) = {
get: "/v1/items/{id}"
};
}
rpc CreateItem(CreateItemRequest) returns (Item) {
option (google.api.http) = {
post: "/v1/items"
body: "*"
};
}
}
message GetItemRequest {
string id = 1;
}
message CreateItemRequest {
string name = 1;
}
message Item {
string id = 1;
string name = 2;
}
- The
(google.api.http)
annotations map gRPC methods to REST paths and HTTP methods. - Save this as
example.proto
in a directory likeproto/
.
2. Generate Code
Compile the .proto
file to generate Go code for gRPC, Connect, and REST handling:
protoc --go_out=. --go_opt=paths=source_relative \
--connect-go_out=. --connect-go_opt=paths=source_relative \
--grpc-go_out=. --grpc-go_opt=paths=source_relative \
proto/example.proto
This generates:
- gRPC service definitions.
- Connect handlers for HTTP/1.1 compatibility.
- Structs for messages.
3. Implement the Service
Create a Go server that implements the gRPC service. For example:
package main
import (
"context"
"log"
"net/http"
examplev1 "path/to/generated/example/v1"
"connectrpc.com/connect"
)
type ExampleServer struct {
examplev1connect.UnimplementedExampleServiceHandler
}
func (s *ExampleServer) GetItem(ctx context.Context, req *connect.Request[examplev1.GetItemRequest]) (*connect.Response[examplev1.Item], error) {
// Fetch item logic (e.g., from a database).
item := &examplev1.Item{Id: req.Msg.Id, Name: "Sample Item"}
return connect.NewResponse(item), nil
}
func (s *ExampleServer) CreateItem(ctx context.Context, req *connect.Request[examplev1.CreateItemRequest]) (*connect.Response[examplev1.Item], error) {
// Create item logic.
item := &examplev1.Item{Id: "new-id", Name: req.Msg.Name}
return connect.NewResponse(item), nil
}
- This server implements the
ExampleService
with basic logic forGetItem
andCreateItem
.
4. Set Up Vanguard Transcoder
Use Vanguard to wrap the service handler, enabling REST and gRPC support. Here’s a complete main.go
:
package main
import (
"log"
"net/http"
"connectrpc.com/vanguard"
examplev1 "path/to/generated/example/v1"
examplev1connect "path/to/generated/example/v1/examplev1connect"
)
func main() {
// Initialize the service implementation.
svc := &ExampleServer{}
// Create a Connect handler for the service.
path, handler := examplev1connect.NewExampleServiceHandler(svc)
// Create a Vanguard service to transcode REST and RPC.
services := []*vanguard.Service{
vanguard.NewService(path, handler),
}
// Initialize the Vanguard transcoder.
transcoder, err := vanguard.NewTranscoder(services)
if err != nil {
log.Fatalf("Failed to create transcoder: %v", err)
}
// Set up HTTP server with Vanguard handler.
mux := http.NewServeMux()
mux.Handle("/", transcoder)
// Start the server.
log.Println("Server starting on :8080...")
if err := http.ListenAndServe(":8080", mux); err != nil {
log.Fatalf("Server failed: %v", err)
}
}
-
Vanguard Service:
vanguard.NewService
wraps the Connect handler, using the generated path and handler. -
Transcoder:
vanguard.NewTranscoder
creates a middleware-like handler that routes and transcodes requests between REST, gRPC, gRPC-Web, and Connect protocols. - The server listens on port 8080 and handles both REST and gRPC requests.
5. Test the API
-
REST Client (using
curl
):
# GET request
curl http://localhost:8080/v1/items/123
# POST request
curl -X POST http://localhost:8080/v1/items -d '{"name": "New Item"}' -H "Content-Type: application/json"
Vanguard transcodes these REST requests to gRPC calls using the HTTP annotations.
-
gRPC Client (using a Go client or
grpcurl
):
grpcurl -plaintext localhost:8080 example.v1.ExampleService/GetItem -d '{"id": "123"}'
The server handles native gRPC requests directly.
6. Optional: Add Compression and Configuration
Vanguard supports compression (e.g., gzip) and custom options. To enable compression:
services := []*vanguard.Service{
vanguard.NewService(path, handler, vanguard.WithCompression(vanguard.CompressionGzip)),
}
You can also configure timeouts or custom codecs if needed.
Key Features of Vanguard
- RESTful Transformation: Supports REST clients by mapping gRPC methods to HTTP endpoints via annotations, ideal for migrating from REST to gRPC.
- Protocol Bridging: Allows gRPC and Connect clients to coexist, useful during transitions.
- Efficiency: Unlike gRPC-Gateway, Vanguard operates within the Go server, reducing overhead and eliminating external dependencies.
- Legacy Support: Can proxy requests to legacy REST backends, enabling gradual migration.
Example Use Case
Suppose you’re migrating a REST API to gRPC. You can:
- Define gRPC methods with HTTP annotations matching existing REST endpoints.
- Use Vanguard to handle both REST and gRPC requests.
- Gradually update clients to use gRPC while maintaining REST compatibility.
Troubleshooting
-
Schema Errors: Ensure the service path matches the Protobuf schema. Use
vanguard.NewServiceWithSchema
for dynamic schemas. -
Content-Type Issues: REST requests must use
application/json
or compatible types. Vanguard validates this automatically. -
Debugging: Enable logging or use tools like
grpcurl
to inspect requests.
Additional Resources
- Vanguard README: Detailed examples and configuration options.
- Connect Documentation: Learn more about Connect protocol and handlers.
- Protobuf HTTP Annotations: Reference for mapping gRPC to REST.
This setup allows you to support both REST and gRPC clients with minimal changes to your server code, leveraging Vanguard’s transcoding capabilities for a smooth transition or hybrid API. _
Let's Connect!!
*Coding examples are AI generated.