GRPC Gateway Client Generator

GRPC Gateway Client Generator Cover Image

gRPC is a very popular alternative to REST for two reasons: high performance and code generation. High performance is achieved by using HTTP/2, which is a binary protocol that is more efficient than HTTP/1.1. Code generation is achieved by using Protocol Buffers that allow the generation of strongly typed client and data transfer objects for many languages.

If you use Golang, gRPC is arguably the best strongly typed API framework. The API performance improvement brought by HTTP/2 is also a nice enhancement. However, using the binary protocol and HTTP/2 is not always an option. It is challenging to consume gRPC API from a browser. If you are building an external API and want to lower the entry barrier for your users, then REST is still a safer choice.

Luckily there's a way to get the best of both worlds. You can build your API using gRPC and convert it to REST using grpc-gateway - an awesome open-source project that translates gRPC service definition to REST API. With grpc-gateway you can use gRPC to leverage code generation but still, expose a REST API to our users.

No problems with consuming our API from a browser anymore! However, if you need to consume your REST API from a Golang-based CLI tool, we can no longer use a generated client. Unfortunately, this is precisely the problem we've faced while building the Akuity Platform. The only solution we found is to generate an OpenAPI specification from gRPC and then use it to generate a Golang client.

What Is Missing in a Two-Layer Approach?

Unfortunately, this two-layer translation introduces unnecessary complexity and noise, significantly hurting generated client quality. We've tried multiple ways to generate OpenAPI specifications and many different Golang client generators. No luck.

We value developer productivity a lot so we decided to build our own solution. Please welcome the Akuity GRPC Gateway Client!

Akuity GRPC Gateway Client

The main idea is to eliminate the middleman and generate high-quality Golang clients directly from the gRPC service definition. This approach allows us to reduce the number of tools involved in the generation and make sure that generated client is almost identical to the original gRPC definition.

The best way to describe the tool is to show it in action!

Try It In Action

The source code of the usage example is available at grpc-gateway-client/example. This example contains a simple gRPC service and a CLI tool that consumes it. The service is a classic "Hello World" service that accepts a name and returns a greeting:

syntax = "proto3";

package helloworld;

import "google/api/annotations.proto";

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      get: "/v1/example/echo"
    };
  }
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

There are several ways to generate a gRPC service from the definition. We are big fans of buf, so we will use it in our example. In order to use the client generator, we need to install the generator binary using go install github.com/akuity/grpc-gateway-client/protoc-gen-grpc-gateway-client@latest and configure it in buf.generate.yaml:

version: v1
managed:
  enabled: true
  go_package_prefix:
    default: github.com/akuity/grpc-gateway-client/internal/test/gen
    except:
      - buf.build/googleapis/googleapis
      - buf.build/grpc-ecosystem/grpc-gateway
plugins:
  - name: grpc-gateway-client
    path: bin/protoc-gen-grpc-gateway-client
    out: internal/test/gen
    opt:
      - paths=source_relative

Now we can generate the client using buf generate and use it in our CLI tool:

client := grpc_gateway_client_example.NewGreeterGatewayClient(gateway.NewClient(baseURL))
resp, err := client.SayHello(context.Background(), &grpc_gateway_client_example.HelloRequest{Name: "World"})
if err != nil {
    panic(err)
}
println(resp.Message)

Conclusion

We hope that you will find this tool useful! If you have any questions or suggestions, please file an issue inside the grpc-gateway-client Github repository. Don't forget to ⭐ the repository if you like it!

Share this blog:

Latest Blog Posts

What's New in Kargo v0.5.0

What's New in Kargo v0.5.0

We're back from Kubecon EU '24 in Paris, and there was a lot of buzz around Kargo! We had many conversations with folks talking about their struggles with how…...

Argo CD CDK8S Config Management Plugin

Argo CD CDK8S Config Management Plugin

If you haven't stored raw kubernetes YAML files in your GitOps repository, you most probably used some sort of tooling that generates YAML files, for example…...

Application Dependencies with Argo CD

Application Dependencies with Argo CD

With Argo CD and GitOps gaining wide adoption, many organizations are starting to deploy more and more applications using Argo CD and GitOps in their workflows…...

Leverage the industry-leading suite

Contact our team to learn more about Akuity Cloud