GCP – From gRPC to RESTful APIs: Expose your gRPC services to the REST of the world
When designing a modern microservice architecture, performance is obviously key. Even outside of high-frequency trading and near-real time systems, extra milliseconds in inter-service communication matter a lot for the overall user experience. In this environment, gRPC has emerged as a high-performance communication protocol and is widely adopted for its low latency, efficient serialization and strongly typed messages.
On the other hand we need to acknowledge that most of the inter-service communications across system boundaries still heavily rely on HTTP APIs. That’s because the APIs largely serve as a contract between decoupled entities in the form of API producers and consumers, and changing them to gRPC would introduce a lot of friction. Additionally, not all developers are equipped or experienced enough to consume gRPC services. API providers would therefore risk missing out on a potential audience by limiting themselves to exposing gRPC services only.
In this blog we demonstrate how to easily bridge the gap between the highly-performant gRPC services and the widely adopted ecosystem of RESTful HTTP APIs. We propose a solution that leverages an automatically generated gRPC gateway that can be deployed alongside the existing gRPC service to handle the protocol translation that will provide an HTTP interface. Finally, we introduce Apigee as the enterprise API management platform to expose a clean RESTful API facade in a secure and self-service manner.
gRPC-to-HTTP gateway
Let’s assume that over the course of its operation, a fictitious company operating an e-commerce site realized that some of the components could provide value on their own and be included in their strategic API economy efforts. Our example is based on a sample microservices architecture that is composed of a range of sub-components written in different programming languages. The first service that they want to explore onboarding on to their API platform is the currency service. It provides two gRPC methods that lets clients list the supported currencies and perform a currency conversion from one currency to another.
As mentioned in the introduction, gRPC services are a popular choice for internal or so called “east-west” service-to-service communications. While gRPC exhibits superior performance characteristics, a significant number of APIs currently utilize HTTP as their primary communication protocol. Migrating these APIs to gRPC would require a substantial investment of resources, particularly considering that not all developers are familiar with the gRPC framework.
To overcome this challenge, we want to provide an adapter layer that provides a more traditional JSON HTTP-based API for the service. Instead of manually writing the protocol translation ourselves, we decided to use the open-source gRPC gateway project to automatically generate an adapter for our use case. The gateway is based off of a .proto file that specifies the services and messages. It serves as the single source of truth — or contract — between the service producer and consumers. To simplify generating the gateway, we created a convenience wrapper that allows us to generate the gateway by providing it a reference to the .proto file.
<ListValue: [StructValue([(‘code’, ‘./generate-gateway.sh –proto-path ./examples/currency.proto’), (‘language’, ”), (‘caption’, <wagtail.rich_text.RichText object at 0x3e329a88dd30>)])]>
The above command parses the supplied .proto file and generates the go module for translating an incoming HTTP REST request to gRPC and sending it to the specified endpoint. Finally, it wraps the gateway in a go module that can be deployed independently.
For the final architecture we’ll want to build a container image and deploy to a target runtime such as Cloud Run. To understand how the gateway works we can also run it locally:
<ListValue: [StructValue([(‘code’, ‘(cd generated/gateway && docker build . -t gateway:latest)rndocker run -p 8080:8080 -e GRPC_SERVER_ENDPOINT=localhost:9090 gateway:latest’), (‘language’, ”), (‘caption’, <wagtail.rich_text.RichText object at 0x3e329a88dbb0>)])]>
The GRPC_SERVER_ENDPOINT environment variable here points to the gRPC endpoint that the gateway should send traffic to. In this case, we’ve already got the gRPC currency service running locally on port 9090. With the gateway started up, you can now send a regular JSON HTTP request to the gateway’s endpoint:
<ListValue: [StructValue([(‘code’, ‘curl -X POST localhost:8080/hipstershop.CurrencyService/Convert -d ‘{“from”: {“units”: 3, “currency_code”: “USD”, “nanos”: 0}, “to_code”: “CHF”}”), (‘language’, ”), (‘caption’, <wagtail.rich_text.RichText object at 0x3e329a88dee0>)])]>
As we can see, we’ve made our gRPC currency service available as a JSON HTTP API that can be easier to use within a wider API ecosystem. However, there’s still room for improvement when we consider how this new API aligns with the company’s well-established API strategy:
The API doesn’t follow the widely accepted RESTful API design principles and still largely reflects the structure of the original .proto specification.
The API doesn’t support API management features such as authentication, centralized logging and monitoring, error handling, or monetization.
Developers don’t have access to a self-service option that allows them to discover new APIs and onboard themselves as API consumers.
Lower entry barriers with API management
To achieve some of these capabilities and ultimately drive adoption of the API, we can leverage an API management layer in the form of an Apigee API Proxy facade. While Apigee can natively expose gRPC services in pass-through mode, here we operate on the previously converted protocol that allows us to apply a range of useful policies and configurations for:
Method, path and payload translations that allow us to provide a proper RESTful facade and abstracts the underlying message format of gRPC
Collection of metrics and rich analytics data to measure the operational performance and success of the API program
Consistent API security, error handling and traffic management controls to protect other systems and impose quotas on clients
To build on top of our gRPC gateway, we first need the API proxy to securely access our gRPC gateway, which could be deployed to Cloud Run where authentication can be enforced with Cloud IAM. With this security mechanism, our API proxy must be configured to use Google Cloud authentication itself, or forward on the credentials received from the API client.
Apigee’s flexible and comprehensive approach to managing routes with an API proxy allows us to expose a RESTful path to API consumers and rewrite the path at runtime to what our gRPC gateway expects.
<ListValue: [StructValue([(‘code’, ‘curl -X POST “https://$APIGEE_HOSTNAME/currency/v1/convert” -d ‘{“from”: {“units”: 3, “currency_code”: “USD”, “nanos”: 0}, “to_code”: “CHF”}”), (‘language’, ”), (‘caption’, <wagtail.rich_text.RichText object at 0x3e329a88d5e0>)])]>
Proxying our currency service through an Apigee API proxy results in the automatic collection of API metrics and analytics data, providing us with rich insights into the health and success of our APIs. We can also build on our API proxy by attaching additional traffic management, security, mediation and even code extension policies.
To introduce and promote this API to a new audience, we can leverage Apigee’s developer portal to publish an API product for developers to discover, explore and experiment with the API, opening up new opportunities. To build on this further, we can optionally monetize an API product to unlock additional revenue streams with a variety of different strategies, such as usage-based pricing or subscription plans.
Conclusion and next steps
In conclusion, we have demonstrated how gRPC services can be easily exposed to new audiences as HTTP APIs, while also leveraging the benefits of a comprehensive API management platform like Apigee. By combining the performance of gRPC with the familiarity and tooling of REST APIs, we can unlock new possibilities for our services and data, reaching a wider range of developers and applications. By embracing this hybrid approach, we can bridge the gap between gRPC and REST when building out an API ecosystem, so you can leverage the best of both worlds.
If you’re interested, you can now put this to the test by carrying out the steps in the Apigee DevRel example.
Read More for the details.