Ra
தமிழ்
← Back to articles

Building a REST API That Talks gRPC Under the Hood — The Go + Kubernetes Way

Building a REST API That Talks gRPC Under the Hood — The Go + Kubernetes Way

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 a GetUser 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.