Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
22 Aug 2025 · 6 min read ·Article 75 / 110
Go

75. Case Study: An API Gateway for a gRPC Service

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

75. Case Study: An API Gateway for a gRPC Service

The need for systems that are scalable, maintainable, and high-performing has pushed many companies to adopt a microservices approach. One of the most popular technologies for service-to-service communication is gRPC, especially for internal interactions that prioritize efficiency and a contract-first API. However, gRPC is not particularly friendly for public consumption or for traditional clients such as web browsers or mobile apps, which are accustomed to HTTP/JSON protocols. Another common challenge is controlling access, authentication, data transformation, monitoring, and so on through a single entry point (the API Gateway). In this case study, we will discuss the design and a simple implementation of an API Gateway for a gRPC Service.


Problem Statement

Suppose you are building a core banking system with several microservices, one of which is a gRPC-based AccountService. External clients (such as a web front-end or a mobile app) can only communicate via REST. You need an API Gateway that:

  • Converts REST requests into gRPC requests.
  • Exposes RESTful endpoints so they can be easily integrated into front-ends and public clients.
  • Handles authentication/authorization at the gateway.
  • Is easy to scale and monitor.

System Flow Diagram

MERMAID
flowchart LR
    A[Client (Web/Mobile)] -- HTTP/JSON --> B(API Gateway)
    B -- gRPC --> C[gRPC AccountService]
    C -- Response gRPC --> B
    B -- HTTP/JSON --> A

Approach: Scenario and Tools

For this case study, we will use:

  • gRPC: As the primary backend service.
  • Envoy Proxy or grpc-gateway: As the API Gateway.
  • Go: The implementation language, thanks to its solid tooling support for gRPC and grpc-gateway.
  • JWT Auth: To simulate authentication.

Defining the Service: AccountService

Let’s start by defining the contract (protobuf) for AccountService.

protobuf
 1// account.proto
 2syntax = "proto3";
 3
 4package account;
 5
 6service AccountService {
 7  rpc GetAccount(GetAccountRequest) returns (GetAccountResponse) {}
 8}
 9
10message GetAccountRequest {
11  string account_id = 1;
12}
13
14message GetAccountResponse {
15  string account_id = 1;
16  string name = 2;
17  double balance = 3;
18}

After writing the account.proto file, generate the server (and client) stubs using the protoc plugin.


1. Implementing the gRPC Service

Create a simple server implementation in Go.

go
 1// account_server.go
 2package main
 3
 4import (
 5	"context"
 6	pb "path/to/accountpb"
 7)
 8
 9type server struct {
10	pb.UnimplementedAccountServiceServer
11}
12
13func (s *server) GetAccount(ctx context.Context, req *pb.GetAccountRequest) (*pb.GetAccountResponse, error) {
14	// Simulated database lookup
15	if req.GetAccountId() == "123" {
16		return &pb.GetAccountResponse{
17			AccountId: "123",
18			Name:      "Jane Doe",
19			Balance:   2500000.0,
20		}, nil
21	}
22	return nil, status.Error(codes.NotFound, "account not found")
23}

2. Why Not Use REST Directly?

A common question: Why not expose this gRPC service directly as REST?
The answer is: gRPC is more efficient (binary, multiplexing), easier to work with in a contract-first manner, and supports streaming. However, not every client can speak gRPC natively. That is why an API Gateway is a clean bridging solution.


3. An API Gateway with grpc-gateway

gRPC-Gateway is an open-source project that generates an HTTP RESTful “reverse-proxy” to gRPC endpoints.

Additions to the Proto File

Add HTTP annotations to the proto:

protobuf
1import "google/api/annotations.proto";
2
3service AccountService {
4  rpc GetAccount(GetAccountRequest) returns (GetAccountResponse) {
5    option (google.api.http) = {
6      get: "/v1/accounts/{account_id}"
7    };
8  }
9}

Running the Gateway

  • Run the gRPC server on a port such as :9090.
  • Run the grpc-gateway server on a port such as :8080, which will forward requests to the gRPC server.

main.go:

go
 1package main
 2
 3import (
 4	"context"
 5	"log"
 6	"net/http"
 7
 8	gw "path/to/accountpb"
 9	"google.golang.org/grpc"
10	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
11)
12
13func main() {
14	grpcEndpoint := "localhost:9090"
15	ctx := context.Background()
16	ctx, cancel := context.WithCancel(ctx)
17	defer cancel()
18
19	mux := runtime.NewServeMux()
20	opts := []grpc.DialOption{grpc.WithInsecure()}
21	err := gw.RegisterAccountServiceHandlerFromEndpoint(ctx, mux, grpcEndpoint, opts)
22	if err != nil {
23		log.Fatalf("failed to start HTTP gateway: %v", err)
24	}
25
26	http.ListenAndServe(":8080", mux)
27}

4. Simulating a Request

Imagine a client sends an HTTP GET request to /v1/accounts/123:

http
1GET /v1/accounts/123
2Authorization: Bearer <jwt_token>

The API Gateway will:

  • Translate the HTTP request into the gRPC GetAccount call.
  • Add or validate authentication (in the interceptors).
  • Return the result to the client in JSON format.

Response example:

json
1{
2  "account_id": "123",
3  "name": "Jane Doe",
4  "balance": 2500000.0
5}

5. Middleware: Auth & Logic at the Gateway

Place middleware centrally at the API Gateway so that downstream services stay simple.

go
 1// HTTP middleware for JWT validation
 2type AuthMiddleware struct {
 3	Next http.Handler
 4}
 5
 6func (am *AuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 7	auth := r.Header.Get("Authorization")
 8	if !ValidateJWT(auth) {
 9		http.Error(w, "Unauthorized", http.StatusUnauthorized)
10		return
11	}
12	am.Next.ServeHTTP(w, r)
13}
14
15// Addition to main.go
16authHandler := &AuthMiddleware{Next: mux}
17http.ListenAndServe(":8080", authHandler)

6. Using Envoy as an Alternative API Gateway

Besides grpc-gateway (which is well suited for prototyping or a Go stack), you can use Envoy for production-grade deployments. Envoy can be configured for HTTP-to-gRPC transcoding, rate limiting, JWT validation, and more.

yaml
 1# Envoy config snippet for HTTP-gRPC transcoding
 2static_resources:
 3  listeners:
 4    - address:
 5        socket_address: { address: 0.0.0.0, port_value: 8080 }
 6      filter_chains:
 7        - filters:
 8            - name: envoy.filters.network.http_connection_manager
 9              typed_config:
10                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
11                route_config:
12                  #...
13                http_filters:
14                  - name: envoy.filters.http.grpc_json_transcoder
15                    typed_config:
16                      "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder
17                      proto_descriptor: "/etc/protos/account.pb"
18                      services: ["account.AccountService"]
19                      print_options:
20                        add_whitespace: true

Comparison Table

Here is a summary comparing the API Gateways commonly used for gRPC services:

GatewayLanguageStrengthsWeaknessesAdvanced Features
grpc-gatewayGoSimple, native GoLimited complex TLS support, Go-onlyLogging, Auth (custom)
Envoy ProxyC++Performant, production provenMore complex configurationRate limit, JWT
KongLua/GoBroad plugin ecosystemHeavier on resourcesRate limit, Auth

7. Scaling and Monitoring

For production capacity:

  • The gateway can be packaged in a container and then scaled horizontally via Kubernetes.
  • The gRPC service can be scaled independently.
  • Monitor incoming/outgoing requests at the gateway, with audit logs, latency metrics, and so on.

Conclusion

An API Gateway for a gRPC service allows us to:

  • Use gRPC internally for performance and maintainability.
  • Provide a REST API for external clients without having to modify each microservice.
  • Apply authentication, logging, monitoring, and business logic through a single entry point.
  • Stay infrastructure-agnostic; it can be swapped out for Envoy or another implementation as needed.

With this approach, developers can focus on the core business logic within each service while security, observability, and device compatibility remain in good shape.


Conclusion

This case study is a simple reflection of one of the best-practice patterns in modern backend architecture. By leveraging an API Gateway as a bridge between the RESTful world and gRPC, you can keep your system modular and future-proof. Experiment and explore with various gateways, and find the trade-offs that best fit your needs. We hope this case study inspires the architectural design and execution of your next project!

Related Articles

💬 Comments