Equinox IT Blog

gRPC - A Contract-First Alternative That's Already Here

gRPC - A Contract-First Alternative That's Already Here
5:43

For nearly two decades, “REST” has often been used as shorthand for HTTP endpoints that return JSON. Ideas originating in Roy Fielding’s architectural work have gradually been conflated with a broader set of API design practices, until REST has come to mean little more than resource-shaped JSON exchanged over HTTP.

gRPC - A Contract-First Alternative That's Already Here

The limitations of this interpretation are well documented, and there is no need to re-litigate the critiques raised by Fielding, Fowler and many others. Nor should the value these approaches have delivered be dismissed — they have shaped the modern web, enabled interoperability at scale, and remain enormously influential. For many teams, they are a pragmatic and productive default.

Nonetheless, complexity and misunderstanding mean that most implementations fall well short of being truly RESTful.

But it is worth asking a different question.

What if we had a type-safe, language-agnostic, contract-first protocol for remote communication over HTTP — one designed explicitly around schema evolution, strong tooling, and long-lived compatibility?

That alternative already exists.

Enter gRPC

gRPC is a modern, open-source, high-performance Remote Procedure Call (RPC) framework built on HTTP/2. Services are defined once in a .proto file using Protocol Buffers (protobuf), and tooling generates strongly typed client and server code for many languages.

In .NET, gRPC is deeply integrated with ASP.NET Core (DI, logging, authentication/authorisation, health checks, etc.), which makes it a practical option for internal service-to-service APIs.

A Small Contract, Generated Everywhere

A minimal protobuf service definition might look like this:

syntax = "proto3";

package hello.v1;

service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
string name = 1;
}

message HelloReply {
string message = 1;
}

And the corresponding server implementation in ASP.NET Core looks like this:

public sealed class GreeterService : Greeter.GreeterBase
{

public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
=> Task.FromResult(new HelloReply { Message = $"Hello {request.Name}" });
}

No controller boilerplate, no hand-written client libraries, and far fewer "did we serialise this the same way?" surprises. You start from a schema, generate code, and let the compiler enforce the contract.

Typed Interfaces and Interoperability (With Real Versioning Rules)

Protobuf gives you a language-neutral schema and a compact wire format. That doesn't mean "anything goes" - it comes with clear compatibility rules. Teams that treat .proto files as stable contracts (and follow protobuf best practices for evolution) tend to see more consistent interoperability than teams relying on loosely versioned JSON conventions.

Performance and Streaming - Where gRPC Shines

gRPC uses:

  • HTTP/2 (multiplexing, header compression, long-lived connections).
  • Binary protobuf payloads (compact and fast to parse compared to many JSON workloads).

In practice, this often results in lower latency and higher throughput for service-to-service calls, especially for "chatty" internal APIs. Microsoft's guidance is clear that gRPC has strengths here - but also that it is not a universal replacement for HTTP/JSON APIs.

Streaming is a first-class feature in gRPC (server streaming, client streaming, and bidirectional streaming). This is a natural fit when you want long-lived, push-based communication patterns. It's worth noting that you can achieve streaming behaviours with HTTP in other ways (for example, Server-Sent Events or WebSockets), but gRPC makes it part of the core contract model.

The AI Connection (Without the Hype)

Modern AI systems often need:

  • Token-by-token streaming responses.
  • Incremental updates (progress, partial results, telemetry).
  • Long-running or interactive workflows between services.

Many teams already do this over HTTP streaming, but gRPC's structured streaming can be a strong fit for internal AI platforms and agent systems where you control both ends of the connection and want a typed contract.

Beyond RPC - Protobuf as a Shared Contract Language

Protobuf isn't married to gRPC. It can also serve as a contract format for events and messages (for example, in Kafka ecosystems via schema registries), helping teams standardise payloads across request/response and event-driven workflows.

That said, adopting protobuf as a "canonical wire format" is a deliberate architectural choice. It can reduce inconsistency, but it also commits you to tooling, schema governance, and compatibility discipline.

Tooling and Testing - It's No Longer a Weak Spot

One of HTTP/JSON's enduring strengths is the tooling ecosystem. gRPC's binary payloads can feel less approachable at first - but the tooling is now very good.

Practical options include:

  • grpcurl - command-line interaction with gRPC services.
  • grpcui - a browser-based UI built on top of grpcurl.
  • Postman - includes a gRPC client interface.
  • Insomnia - supports gRPC requests.
  • Kreya - a desktop client for gRPC/REST/WebSockets (local-first workflows).

Cake and Eat It

gRPC does provide a REST/JSON fallback mechanism via HTTP transcoding, allowing a single gRPC service definition to be exposed simultaneously as conventional HTTP endpoints. In theory, this offers an appealing bridge: a strongly typed, contract-first internal interface with a familiar REST-shaped façade for external consumers. In practice, however, this fallback is rarely a compelling way to arrive at REST. The generated HTTP surface is constrained by the gRPC contract, tends toward RPC semantics rather than resource-oriented design, and often feels awkward when forced into REST conventions it was never designed to honour. That said, in specific situations — particularly where an organisation wants to preserve gRPC as the primary system of record while offering limited interoperability, tooling compatibility, or gradual migration paths — transcoding can be a pragmatic compromise. It is less a replacement for thoughtfully designed REST APIs, and more a tactical concession: not a best-of-both-worlds solution, but occasionally a useful way to keep both worlds in play.

Why It Matters

In practice, many ‘REST APIs’ function less as protocols and more as tightly coupled JSON contracts, with the operational and versioning risks that implies.

gRPC isn't "the new REST". It's a strong, mature option for a specific set of problems:

  • Internal service-to-service APIs.
  • Polyglot environments where code generation pays off.
  • Low-latency, high-throughput communication.
  • Streaming-first workflows.

In ASP.NET Core, getting started really is simple:

app.MapGrpcService<MyService>();

You still need to make real engineering decisions around authentication, authorisation, retries/timeouts, observability, schema evolution, and operational compatibility (for example, browser access and certain proxies/load balancers).

Adopt it where it fits - and it can remove a surprising amount of accidental complexity from distributed systems. Denying the ubiquity of REST would be foolish, but the value of gRPC is incredibly accessible.

 

Subscribe by email