gRPC-Web, Connect and REST gateways

gRPC · Advanced · 12 min

Most products need the same API in browsers and for third parties, not just between services.

Browsers cannot control HTTP/2 framing or read trailers from fetch, so they cannot speak native gRPC. Options:

  • gRPC-Web: a variant protocol that browsers can use, translated to gRPC by a proxy (Envoy has a built-in filter) or supported directly by some servers. It supports unary and server-streaming calls, not client or bidirectional streaming.
  • Connect (connectrpc.com): a protocol and set of libraries from Buf. Connect servers speak gRPC, gRPC-Web and the Connect protocol, a simple HTTP POST with JSON or binary bodies that you can even call with curl. Generated TypeScript clients work in browsers without a proxy.
  • HTTP/JSON transcoding: annotate methods with google.api.http options (get: "/v1/users/{id}") and let grpc-gateway (Go), Envoy's transcoder or cloud API gateways expose a REST API that maps onto the gRPC service. You can also generate OpenAPI from the same annotations.

Protobuf has a canonical JSON mapping: lowerCamelCase field names, 64-bit integers as strings, enums as names, Timestamp as RFC 3339 strings. Gateways and tools rely on it, so learn its rules.

Choose based on consumers: Connect for your own web and mobile apps, transcoding for public REST APIs, gRPC-Web when an Envoy-based stack is already in place.

Example

syntax = "proto3";
package users.v1;

import "google/api/annotations.proto";

service UserService {
  rpc GetUser(GetUserRequest) returns (User) {
    option (google.api.http) = { get: "/v1/users/{id}" };
  }
  rpc CreateUser(CreateUserRequest) returns (User) {
    option (google.api.http) = { post: "/v1/users" body: "user" };
  }
}

message GetUserRequest { string id = 1; }
message CreateUserRequest { User user = 1; }
message User { string id = 1; string display_name = 2; int64 karma = 3; }

// GET /v1/users/42 via a transcoding gateway returns canonical JSON:
// { "id": "42", "displayName": "Ann", "karma": "1200" }  <- int64 as string

Remember

  • Browsers need gRPC-Web or Connect, not native gRPC
  • Connect servers speak gRPC, gRPC-Web and a simple HTTP protocol
  • google.api.http annotations drive REST transcoding
  • Proto JSON: camelCase names, int64 as strings

Watch out for

  • Expecting client-streaming or bidirectional calls to work over gRPC-Web.

Check yourself

  1. Why does proto's JSON mapping encode int64 values as strings?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: grpc.io/docs/platforms/web/

Builds on

Unlocks

Nothing builds on this yet.