gRPC vs REST

Intermediate
Application Layer

REST uses HTTP/1.1 with JSON — human-readable, universally supported, but verbose. gRPC uses HTTP/2 with Protocol Buffers — binary, strongly typed, 5–10× faster, and supports bidirectional streaming.

Overview

REST (Representational State Transfer) over HTTP/1.1 with JSON is the dominant style for public APIs — easy to consume, debuggable with curl, and supported by every language. But JSON is verbose (field names repeated in every response) and HTTP/1.1 lacks multiplexing. gRPC, created by Google, addresses these shortcomings: it uses Protocol Buffers (protobuf) for binary serialisation (3–10× smaller payloads), HTTP/2 for multiplexed streams, and generates strongly-typed client/server stubs from a .proto schema. gRPC supports four interaction patterns: unary (like REST), server streaming, client streaming, and bidirectional streaming. It is the default for inter-service communication in Google, Netflix, and most Kubernetes-native microservices. The trade-off: gRPC is harder to debug (binary, not human-readable), requires HTTP/2 (complicates load balancer setup), and is not supported natively in browsers (requires gRPC-Web proxy). REST remains preferable for public-facing APIs; gRPC shines for internal service-to-service communication.

Protocol Buffers and Code Generation

gRPC defines services in a .proto file. The protoc compiler generates type-safe client and server stubs in any language. The binary wire format is compact and fast to serialise/deserialise compared to JSON text parsing.

Protobuf service definition and Java gRPC server
// user.proto — service definition
syntax = "proto3";
package user;

service UserService {
  rpc GetUser(GetUserRequest) returns (UserResponse);                    // Unary
  rpc ListUsers(ListUsersRequest) returns (stream UserResponse);        // Server streaming
  rpc UpdateUsers(stream UpdateUserRequest) returns (UpdateSummary);   // Client streaming
  rpc Chat(stream ChatMessage) returns (stream ChatMessage);           // Bidirectional
}

message GetUserRequest { string user_id = 1; }
message UserResponse {
  string id      = 1;
  string name    = 2;
  string email   = 3;
  int64  created = 4;
}

// Compile: protoc --java_out=. --grpc-java_out=. user.proto
// Generates: UserServiceGrpc.java (stubs), UserProto.java (POJOs)

// Java gRPC server (Spring Boot with grpc-spring-boot-starter):
@GrpcService
public class UserGrpcService extends UserServiceGrpc.UserServiceImplBase {
    @Override
    public void getUser(GetUserRequest req, StreamObserver<UserResponse> observer) {
        UserResponse response = UserResponse.newBuilder()
            .setId(req.getUserId())
            .setName("Alice")
            .setEmail("alice@example.com")
            .build();
        observer.onNext(response);
        observer.onCompleted();
    }
}

gRPC vs REST Comparison

Choosing between gRPC and REST depends on the consumer (browser vs service), need for streaming, and team tooling. Many organisations use both: REST for public APIs, gRPC for internal microservice communication.

gRPC vs REST table and Java gRPC client stub
// gRPC vs REST comparison:
// ┌─────────────────────┬──────────────────────┬──────────────────────┐
// │ Property            │ REST + JSON           │ gRPC + Protobuf      │
// ├─────────────────────┼──────────────────────┼──────────────────────┤
// │ Protocol            │ HTTP/1.1 or HTTP/2   │ HTTP/2 required      │
// │ Payload format      │ JSON (text)           │ Protobuf (binary)    │
// │ Payload size        │ Larger                │ 5–10× smaller        │
// │ Performance         │ Baseline              │ ~5–10× faster        │
// │ Streaming           │ No (SSE workaround)   │ Yes (4 modes)        │
// │ Type safety         │ No schema (OpenAPI)   │ Strict .proto schema │
// │ Browser support     │ Native                │ gRPC-Web proxy needed│
// │ Debugging           │ Easy (curl, Postman)  │ Hard (binary)        │
// │ Code generation     │ Optional (OpenAPI)    │ Required (protoc)    │
// │ Best for            │ Public APIs, browser  │ Internal services    │
// └─────────────────────┴──────────────────────┴──────────────────────┘

// Java gRPC client (blocking stub):
ManagedChannel channel = ManagedChannelBuilder
    .forAddress("user-service", 9090)
    .usePlaintext()                         // use .useTransportSecurity() in prod
    .build();

UserServiceGrpc.UserServiceBlockingStub stub = UserServiceGrpc.newBlockingStub(channel);
UserResponse user = stub.getUser(
    GetUserRequest.newBuilder().setUserId("u-123").build()
);
System.out.println(user.getName());         // type-safe — no JSON parsing

Key Points to Remember

  • 1gRPC uses HTTP/2 + Protobuf; REST typically uses HTTP/1.1 + JSON.
  • 2Protobuf payloads are 5–10× smaller and faster to serialise than JSON.
  • 3gRPC supports 4 patterns: unary, server streaming, client streaming, bidirectional.
  • 4gRPC requires HTTP/2 — complicates some load balancer and proxy setups.
  • 5Browsers cannot use gRPC natively — require gRPC-Web proxy (Envoy).
  • 6Common pattern: REST for public APIs, gRPC for internal microservice-to-microservice calls.

Interview Questions

Sign in to ask Aria
1

What are the main differences between gRPC and REST?

MediumThoughtWorks
2

Why does gRPC require HTTP/2?

MediumAmazon
3

What are the four communication patterns supported by gRPC?

MediumFlipkart
4

When would you choose gRPC over REST for microservice communication?

MediumRazorpay
5

How would you expose a gRPC service to a browser-based frontend?

HardEqual Experts

Ask Aria about gRPC vs REST

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…