Core Java

Implementing gRPC to REST Gateway in Java

gRPC is an efficient binary protocol ideal for internal microservices communication. However, many clients and partners still expect RESTful APIs over HTTP/JSON.

Instead of maintaining duplicate services, you can expose your gRPC APIs as REST endpoints. This hybrid approach gives you the best of both worlds: high-performance internal communication and familiar REST for external consumers.

In this guide, you’ll learn:

  • Why you’d want a gRPC–REST gateway
  • The main architectural approaches
  • How to use grpc-gateway and Envoy as protocol translators
  • Example configurations to get started
  • Best practices for maintainable APIs

Why Bridge gRPC and REST?

gRPC Advantages:

  • HTTP/2 multiplexing
  • Protobuf contracts
  • Streaming capabilities
  • Strong typing

REST Advantages:

  • Ubiquitous tooling
  • Easy to call from browsers or mobile apps
  • Human-readable JSON payloads

Common Use Cases:

  • Internal services use gRPC
  • External clients or legacy systems require REST
  • Incrementally migrating to gRPC

Architectural Options

There are two main patterns to expose REST over gRPC:

1️⃣ grpc-gateway (Go-based)

  • Generates a reverse proxy server translating HTTP/JSON into gRPC.
  • Reads your .proto files.
  • Generates REST handlers automatically.
  • Usually deployed alongside your Java gRPC server.

Pros:

  • Simpler for greenfield projects.
  • Protobuf annotations drive REST mapping.

Cons:

  • The gateway runs in Go, separate from your Java server.
  • Requires additional deployment and build tooling.

grpc-gateway GitHub

2️⃣ Envoy Proxy

  • A high-performance proxy server and service mesh.
  • Uses Envoy’s gRPC-JSON transcoder filter to expose REST.
  • Runs as a standalone sidecar or gateway in Kubernetes.

Pros:

  • Language-agnostic.
  • Powerful routing, load balancing, and observability.
  • First-class Kubernetes support.

Cons:

  • Steeper learning curve.
  • Requires Envoy configuration skills.

Envoy gRPC–JSON transcoding

Example: Defining gRPC Service

Let’s define a simple gRPC service in hello_service.proto:

syntax = "proto3";

package helloworld;

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

Tip: To expose this via REST, you’ll annotate the RPC methods with HTTP bindings (see next section).

Using grpc-gateway (Go Reverse Proxy)

grpc-gateway generates a REST reverse proxy from your .proto definitions.

1️⃣ Annotate Your Service

Update hello_service.proto:

import "google/api/annotations.proto";

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse) {
    option (google.api.http) = {
      post: "/v1/hello"
      body: "*"
    };
  }
}

✅ This declares that HTTP POST /v1/hello maps to SayHello.

2️⃣ Generate Code

Run protoc with grpc-gateway plugins:

protoc -I . \
  -I $GOPATH/src \
  -I $GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  --grpc-gateway_out=logtostderr=true:. \
  hello_service.proto

This generates a Go reverse proxy server that:

  • Receives REST requests.
  • Marshals JSON to Protobuf.
  • Invokes your Java gRPC server.

3️⃣ Deploy

  • Run your Java gRPC server normally (on a port like :50051).
  • Start the Go grpc-gateway server as a separate process (commonly on port :8080).

✅ Incoming HTTP requests to the gateway are translated and proxied to the gRPC server.

Using Envoy for REST Exposure

If you prefer Envoy, you don’t need any Go code—just configuration.

1️⃣ Envoy Configuration

Here’s a minimal envoy.yaml example:

static_resources:
  listeners:
    - name: listener_http
      address:
        socket_address: { address: 0.0.0.0, port_value: 8080 }
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                codec_type: AUTO
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: backend
                      domains: ["*"]
                      routes:
                        - match: { prefix: "/v1/hello" }
                          route: { cluster: grpc_service }
                http_filters:
                  - name: envoy.filters.http.grpc_json_transcoder
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder
                      proto_descriptor: "/etc/envoy/hello_service.pb"
                      services: ["helloworld.HelloService"]
                      print_options:
                        add_whitespace: true
                        always_print_primitive_fields: true
                  - name: envoy.filters.http.router

  clusters:
    - name: grpc_service
      connect_timeout: 0.25s
      type: LOGICAL_DNS
      lb_policy: ROUND_ROBIN
      http2_protocol_options: {}
      load_assignment:
        cluster_name: grpc_service
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: your_grpc_server
                      port_value: 50051

✅ Key points:

  • The proto_descriptor is a compiled descriptor set of your .proto files.
  • Envoy handles HTTP/JSON to gRPC automatically.
  • Routes /v1/hello to your Java gRPC server.

2️⃣ Generate Descriptor Set

Use protoc to generate hello_service.pb:

protoc -I . --include_imports --include_source_info \
  --descriptor_set_out=hello_service.pb \
  hello_service.proto

3️⃣ Run Envoy

Launch Envoy with your config:

envoy -c /path/to/envoy.yaml

✅ You can now POST JSON to http://localhost:8080/v1/hello and get REST responses.

Best Practices

Keep Protobuf Definitions as the Single Source of Truth

  • Avoid duplicating schema in OpenAPI/Swagger.

Document REST Mappings Clearly

  • Use annotations consistently (google.api.http).

Monitor and Log Transcoding

  • Envoy and grpc-gateway provide rich access logs.

Automate Descriptor Generation

  • Include protoc in your CI/CD pipeline.

Secure the Gateway

  • Use HTTPS, authentication, and rate limiting.

Further Reading & Tools

Conclusion

A gRPC-to-REST gateway is an elegant way to expose modern services to REST consumers without maintaining duplicate APIs. Whether you use grpc-gateway or Envoy, you get the flexibility to support clients at any maturity level—all while keeping your internal systems efficient and strongly typed.

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button