We've all been there.
You're building a modern microservices platform. You've embraced gRPC for all the right reasons: it's fast, compact, strongly typed, and great for internal service-to-service communication. Life is good… until someone says:
"Hey, we need to expose this to the outside world as a REST API."
Suddenly, your clean gRPC-only backend needs to speak the language of browsers, frontend teams, and third-party integrators — HTTP/JSON. But you don't want to rewrite your microservices or maintain two sets of code.
So what do you do?
The Problem
- Internal microservices speak gRPC (ideal for internal speed and efficiency)
- External clients need REST (for browser compatibility, third-party access, Postman-friendliness, etc.)
- You want one source of truth, not duplicate implementations
- You're running Go and deploying everything on Kubernetes
The Solution: grpc-gateway
This is where grpc-gateway shines — a Go-powered bridge that converts RESTful HTTP+JSON requests to gRPC, automatically.
You write your .proto
files once, and it generates:
- A gRPC server (as usual)
- A REST gateway server
- Optional OpenAPI/Swagger documentation
How It Works
So your internal microservices stay gRPC, and the gateway becomes the translator at the edge. It's clean, idiomatic, and works beautifully in a Kubernetes-native environment.
A Quick Example
syntax = "proto3";
package user;
import "google/api/annotations.proto";
service UserService {
rpc GetUser(GetUserRequest) returns (UserResponse) {
option (google.api.http) = {
get: "/v1/users/{id}"
};
}
}
message GetUserRequest {
string id = 1;
}
message UserResponse {
string id = 1;
string name = 2;
}
The google.api.http
annotation tells grpc-gateway:
"Hey, when someone hits
/v1/users/123
over HTTP, convert that into aGetUser
gRPC call."
Now all you do is run the protobuf compiler with the right plugins:
protoc -I . \
--go_out . --go-grpc_out . \
--grpc-gateway_out . \
--openapiv2_out . \
user_service.proto
Now you have:
- A
GetUser
gRPC method - A REST endpoint at
/v1/users/{id}
- Auto-generated Swagger docs (yes, you can plug into Swagger UI!)
Deploying on Kubernetes
On K8s, it looks like this:
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 2
template:
spec:
containers:
- name: grpc-server
image: myorg/user-service:latest
ports:
- containerPort: 50051
- name: grpc-gateway
image: myorg/user-gateway:latest
ports:
- containerPort: 8080
You can deploy the gateway as:
- A sidecar inside each microservice pod
- Or as a separate Deployment and let it route to multiple gRPC backends
You then expose it via Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
spec:
rules:
- http:
paths:
- path: /v1/
pathType: Prefix
backend:
service:
name: user-gateway
port:
number: 8080
Production Tips
- Use mTLS with your Ingress controller or service mesh (Istio, Linkerd) for secure gRPC traffic
- Enable Prometheus metrics on both your gateway and gRPC servers
- Use OpenTelemetry for tracing — especially helpful when debugging REST-to-gRPC hops
- If you're versioning APIs, consider structuring REST paths like
/v1/...
and keeping proto files modular
The Reasons This Pattern Is Effective
- REST is given to frontend teams. They can use Postman, Swagger, or simply curl to reach endpoints.
- The speed and clear contract definitions of gRPC appeal to backend developers.
- Only one set of service logic is maintained by platform engineers.
- Scaling, monitoring, and securing the setup is made simple by Kubernetes.
- It's not glue code that you're writing. APIs aren't being duplicated. The smart way is to expose your contract in a variety of formats and take ownership of it.
Wrapping Up
REST and gRPC don't have to be adversaries.
Tools like grpc-gateway enable you to speak both languages fluently when using Go + Kubernetes: gRPC for your internal architecture and REST for the external environment. Furthermore, doing so does not require sacrificing maintainability, performance, or observability.
Our teams have had great success with this configuration; it's the type of system that scales both people and software.