Read the official Jepsen report for Bufstream

Connect: A better gRPC

Jun 1, 2022/6 min read

Today we're releasing Connect, a slim framework for building browser and gRPC-compatible HTTP APIs. Connect is production-ready — focused, simple, and debuggable — and it's fully compatible with gRPC clients and servers. If you're frustrated by the complexity and instability of today's gRPC libraries, we think you'll find Connect a breath of fresh air. connect-go is available now under an Apache 2 open source license, and documentation is available on connectrpc.com. We'll release Connect for TypeScript soon, with more languages to follow.

Another RPC framework?

In the seven years since its announcement, gRPC has brought much-needed consensus to Protobuf RPC. Starting from a soup of competing, mutually incompatible hobby projects, the gRPC team has rallied the community around a common protocol, introduced many developers to RPC-style APIs, and driven the popularity of Protobuf outside Google. Thanks to their tireless efforts, we can specify our APIs with Protobuf, implement them with gRPC, and be confident that most languages will have a compatible client library.

Conceptually, the gRPC protocol is HTTP with Protobuf-encoded bodies and a sprinkling of metadata. Despite that straightforward premise, the protocol and today's gRPC libraries share a maximalist design ethos that has led to extraordinary complexity. Rather than making production systems simple and stable, gRPC over-complicates development, deployment, debugging, and maintenance.

As an example, consider Google's gRPC implementation in Go:

  • Excluding comments, grpc-go is 130 thousand lines of hand-written code. It has dozens of subpackages, nearly a hundred configuration options, and bespoke name resolution and load balancing mechanisms. Just sifting through the kitchen sink of features takes hours, and the sheer quantity of code makes subtle bugs and resource leaks inevitable.
  • Rather than using the Go standard library's net/http, grpc-go uses its own implementation of HTTP/2. It's incompatible with the rest of Go's HTTP ecosystem, so you can't cleanly serve gRPC requests alongside other HTTP traffic and can't use most third-party packages.
  • The gRPC protocol requires end-to-end support for HTTP/2 and trailers. Supporting common HTTP clients — like web browsers — requires elaborate translating proxies.
  • In addition to using obscure HTTP features, the gRPC protocol is difficult to debug. Even with JSON support enabled, simple request-response RPCs mix the JSON you care about with binary framing data. Forget curl | jq or the Chrome network inspector — the available tools are all immature and gRPC-specific.
  • As a policy, grpc-go doesn't follow semantic versioning; the release notes even include a special section for "Behavior Changes." At least four releases in the past year have broken backward compatibility, and prominent gRPC users (including etcd) are often unable to update for months at a time.

Balancing the needs of grpc-go's open source community and Google's internal users is a difficult and thankless task. And perhaps its breadth of features and options are required for adoption within Google. For the rest of us, the complexity and instability of grpc-go represents an unpleasant distraction from our core business.

Production-grade simplicity

Connect brings simplicity back to Protobuf-powered APIs. Each Connect implementation is focused: just the essential features, built on top of time-tested HTTP libraries and designed to get out of your way.

  • In Go, Connect is just one package, with a few thousand lines of code and a handful of commonly-used options. Even the generated code is meant to be read.
  • It's built on net/http. Connect handlers implement http.Handler, and Connect clients wrap http.Client. They work with any third-party router, middleware, or server.
  • On top of net/http's foundation, connect-go supports three RPC protocols: gRPC, gRPC-Web, and Connect's own protocol. Handlers support all three protocols by default, and clients can switch protocols with one config option — no other code changes necessary.
  • The Connect protocol is a simple, POST-only protocol that works over HTTP/1.1 or HTTP/2. It takes the best portions of gRPC and gRPC-Web, including streaming, and packages them into a protocol that works equally well in browsers, monoliths, and microservices. The Connect protocol is what we think the gRPC Protocol should be. By default, JSON- and binary-encoded Protobuf is supported. Calling a Connect API is as easy as using curl:
    # Try it out! This is a live demo!
    curl \
        --header "Content-Type: application/json" \
        --data '{"sentence": "I feel happy."}' \
        https://demo.connectrpc.com/connectrpc.eliza.v1.ElizaService/Say
    
  • connect-go also supports the full gRPC protocol, including streaming, headers, trailers, and error details. gRPC-compatible server reflection and health checks are available as standalone packages. Instead of cURL, we could call our Connect API with grpcurl:
    # This is also a live demo!
    go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
    grpcurl \
        -d '{"sentence": "I feel happy."}' \
        demo.connectrpc.com:443 \
        connectrpc.eliza.v1.ElizaService/Say
    
  • Handlers and clients also support the gRPC-Web protocol, so browsers can connect directly to your server. We validate our gRPC and gRPC-Web implementations using an extended version of Google's own interoperability tests.
  • Headers, trailers, and other metadata are passed explicitly, without attaching anything to Go contexts. With generics, the resulting code is ergonomic, type-safe, and easy to reason about.

If you've used the Buf CLI or Schema Registry, you've used Connect — internally, we've completely replaced grpc-go with connect-go. We've found Connect a joy in production: it's small, simple, and debuggable.

In Go, Connect is currently in beta: we rely on it in production, but we may make a few changes as we gather feedback from early adopters. We're planning to tag a stable v1.0 in October, soon after the Go 1.19 release. We take semantic versioning very seriously: once we release v1.0, we'll never break your builds.

Coming soon

We've got big plans for the Connect ecosystem! Along with Connect in Go, we've been working on a TypeScript implementation for browsers. It shares the same design priorities: it's idiomatic TypeScript all the way down, stays close to the browser's fetch API, fits neatly into React hooks, and supports both gRPC-Web and Connect's own protocol. It also produces tiny bundles. We've already replaced grpc-web in the Buf Schema Registry frontend, and we're planning to release connect-web soon — stay tuned.

Eventually, we'd like to release Connect implementations for Express, Rails, Django, Laravel, and similar frameworks. You shouldn't have to choose between these productive toolkits and Protocol Buffers — they should work seamlessly together.

Get involved!

We'd love to hear what you think of Connect: check out the Getting Started guide, try Connect in your next Go project, poke through the demonstration project, and please file issues if something doesn't work as you expect. We're always available in the Buf Slack, and we're usually in the #grpc and #connect channels in the Gophers Slack too.

Ready for a trial?