Read the official Jepsen report for Bufstream

Introducing Cacheable RPCs in Connect

May 3, 2023/4 min read

Resource caching is an effective strategy to improve performance and reduce load when running a service. Unfortunately, because gRPC requests use POST requests, implementing caching for gRPC services the way one would with RESTful services is often cumbersome or impossible.

As part of our commitment to build a better RPC protocol, we’re pleased to announce that we have expanded the Connect protocol to support the use of HTTP GET requests, enabling web browsers and CDNs to cache Connect requests with ease. Using connect-go 1.7.0 or greater, it is now possible to both handle and make GET requests using RPCs, almost exactly the way it is done today with POST, allowing web browsers and CDN services to cache Connect requests with ease.

In this article, we’ll discuss how to use this feature, where it’s useful, and show how existing gRPC services can be adapted to take advantage of this feature using Envoy.

Getting started with GET requests

To use HTTP GET, RPC methods have to be annotated with the built-in Protobuf idempotency_level option and specify NO_SIDE_EFFECTS . This asserts that the RPC is safe to use as a GET request (which can now be assumed when using both a Connect client and service). For example, here is how one might annotate the PetStore example service:

service PetStore {
  rpc GetPet(GetPetRequest) returns (GetPetResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  rpc PutPet(PutPetRequest) returns (PutPetResponse) {}
  rpc DeletePet(DeletePetRequest) returns (DeletePetResponse) {}
}

With this annotation, when buf generate is invoked with connect-go 1.7 or newer, Connect servers will automatically support HTTP GET requests—no other code modifications are needed.

On the client side, we need to instruct the Connect client to use GET requests. In connect-go, this is done by specifying the WithHTTPGet() option when creating a client:

client := petv1.NewPetStoreClient(
    http.DefaultClient,
    connect.WithHTTPGet(),
)

That’s it! This client will transparently use HTTP GET when PetStore methods without side effects are called.

Reference our documentation for more information.

Benefits of using GET requests with Connect

Now that we’ve discussed how to use GET requests, let’s discuss why one might use GET requests.

  • Caching: GET requests are easy to cache, both in the browser and in most CDNs. It’s easy to set standard response headers like Cache-Control to inform browsers, CDNs, and other middleboxes how to manage caching for a given request, and for how long the response is valid.
  • Ease of use: GET requests with JSON payloads are so easy to formulate, they can be written directly in a browser URL bar. This makes developing and testing programs simpler.

Screenshot of a browser showing a Connect endpoint

  • Lower CORS overhead: Connect GET requests meet the requirements to avoid CORS preflight requests, as they don’t require any non-simple headers and use GET, a simple method. This means fewer network round-trips for RPCs, a big win when dealing with unpredictable latency (such as when communicating over cellular networks).
  • And more! GET requests are versatile; it’s now possible to use Connect with tools that don’t necessarily speak the Connect protocol. Many programs can fetch an arbitrary URL and consume a JSON response; these tools can be used to make Connect GET requests. For example, now it’s possible to make Connect requests inside of Microsoft Power Query, or even use Connect APIs inside of Shortcuts on an iPhone or iPad.

Better gRPC interoperability with Envoy

Connect clients generally support communicating with vanilla gRPC and gRPC-web servers, but doing so prevents one from taking advantage of features unique to the Connect protocol. Users of the Envoy proxy will be pleased to know that Envoy 1.26 now ships with a Connect-gRPC bridge that allows clients to speak the Connect protocol (including GET requests) to existing gRPC servers. This filter can be used without modifying any existing code. In addition, it doesn’t require configuration, gRPC reflection, or access to the underlying schema. That means it doesn’t need to be re-deployed when the underlying service changes, either—just set it and forget it!

To showcase this new capability, we created a demo showing how to use gRPC-Go with Envoy 1.26 to make GET requests directly to a vanilla gRPC service.

Please note that this bridge filter is brand new and is not yet considered “stable” in Envoy, as it has not seen substantial testing in production environments.

We’re excited to see what these new features can enable and, more importantly, what we can do to continue to make Connect the best RPC protocol. Try the new GET request feature and Envoy filter and let us know what you think via the Buf Slack. We’re always happy to chat about it!

Ready for a trial?