Implementing gRPC Gateway
1. Understanding gRPC Gateway
| Concept | Detail |
|---|---|
| Purpose | Generate REST/JSON proxy from .proto with HTTP annotations |
| Runtime | HTTP server in same process, forwards to gRPC server |
| Alternative | Envoy gRPC-JSON transcoder, Connect-RPC |
2. Generating Gateway Code
Example: buf.gen.yaml entry
plugins:
- remote: buf.build/grpc-ecosystem/gateway
out: gen
opt: paths=source_relative
- remote: buf.build/grpc-ecosystem/openapiv2
out: gen/openapi
3. Creating Gateway Server
Example: Mux + register
mux := runtime.NewServeMux()
_ = userv1.RegisterUserServiceHandlerFromEndpoint(ctx, mux,
"localhost:50051", []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())})
http.ListenAndServe(":8080", mux)
4. Registering Gateway Handlers
| API | Detail |
|---|---|
RegisterXServiceHandler | From existing conn |
RegisterXServiceHandlerFromEndpoint | Dial endpoint |
RegisterXServiceHandlerServer | In-process — no network hop |
5. Adding HTTP Annotations
Example: HTTP rules
service UserService {
rpc GetUser(GetUserRequest) returns (User) {
option (google.api.http) = { get: "/v1/users/{id}" };
}
rpc CreateUser(CreateUserRequest) returns (User) {
option (google.api.http) = { post: "/v1/users" body: "user" };
}
rpc UpdateUser(UpdateUserRequest) returns (User) {
option (google.api.http) = { patch: "/v1/users/{user.id}" body: "user" };
}
}
6. Configuring REST Paths
| Pattern | Effect |
|---|---|
/v1/users/{id} | Path var maps to request.id |
{name=projects/*/users/*} | Resource-name pattern |
additional_bindings | Multiple URL mappings |
7. Mapping HTTP Methods
| RPC Verb | Convention |
|---|---|
| Get / List | GET |
| Create | POST |
| Update | PUT or PATCH |
| Delete | DELETE |
| Custom action | POST with verb in path |
8. Handling Query Parameters
| Rule | Detail |
|---|---|
| Unmapped scalar fields | Become query params automatically |
| Repeated | ?tags=a&tags=b |
| Nested | ?user.id=1 |
9. Handling Path Parameters
| Pattern | Detail |
|---|---|
{id} | Maps to scalar field |
{path=**} | Captures remaining path |
| Validation | Type-checked from proto |
10. Configuring Custom Marshaling
Example: Custom JSON marshaler
mux := runtime.NewServeMux(
runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{
MarshalOptions: protojson.MarshalOptions{EmitUnpopulated: true, UseProtoNames: false},
UnmarshalOptions: protojson.UnmarshalOptions{DiscardUnknown: true},
}),
)
| Option | Effect |
|---|---|
EmitUnpopulated | Include default-valued fields |
UseProtoNames | snake_case vs camelCase |
DiscardUnknown | Ignore unknown JSON fields |