Definition
- REST – synchronous request-response over HTTP/1.1, text-based (JSON), resource-oriented, human-readable, and universally supported by browsers, mobile apps, and third parties.
- gRPC – synchronous request-response over HTTP/2, binary protocol buffers with a strict
.protocontract, strong typing, smaller payloads, and bidirectional streaming support. - Kafka – asynchronous publish-subscribe over a durable, partitioned event log where producers publish to topics and consumer groups read at their own pace.
- Key distinction – REST and gRPC are both synchronous ("call me and wait"); Kafka is asynchronous ("announce it and move on").
- Complementary – these technologies are not competing; a banking system uses REST at the public edge, gRPC for hot internal paths, and Kafka for the event backbone.
At National Bank of India, REST is like sending a clearly written letter in plain language to a specific counter and waiting for the reply: anyone can read it, but it is a bit bulky. gRPC is like a fast, coded form between two bank branches that both understand exactly: tiny, quick, and strict, but an outsider cannot read it. Kafka is like the bank's internal announcement board: a department pins a note that something happened and walks away, and any department reads it whenever it is ready.
Understanding the Concepts
What is REST?
REST stands for Representational State Transfer. It uses HTTP/1.1 and typically JSON for the payload. It is resource-oriented, meaning you model nouns and use HTTP verbs like GET, POST, PUT, and DELETE. REST is the default for public APIs because it is human-readable, easy to cache, and supported by every browser and HTTP client.
package com.bank.controller;
import com.bank.model.Account;
import com.bank.service.AccountService;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
@RestController
@RequestMapping("/api/v1/accounts")
public class AccountController {
private final AccountService accountService;
public AccountController(AccountService accountService) {
this.accountService = accountService;
}
@GetMapping("/{accountId}/balance")
public BigDecimal getBalance(@PathVariable String accountId) {
return accountService.getBalance(accountId);
}
}
GET /api/v1/accounts/SAV2001/balance
Content-Type: application/json
Response: 75000.00
Payload size: ~45 bytes (JSON text)
Latency: ~8ms (HTTP/1.1, new connection)
What is gRPC?
gRPC uses HTTP/2 and binary protocol buffers. You define the service and messages in a .proto file and generate strongly typed client and server stubs. Calls are type-safe at compile time. gRPC supports four call types: unary, server streaming, client streaming, and bidirectional streaming. It is much faster and smaller on the wire than JSON over HTTP/1.1.
// account_service.proto
syntax = "proto3";
package com.bank.grpc;
service AccountService {
rpc GetBalance (BalanceRequest) returns (BalanceResponse);
rpc StreamTransactions (AccountRequest) returns (stream Transaction);
}
message BalanceRequest {
string account_id = 1;
}
message BalanceResponse {
string account_id = 1;
string balance = 2;
}
message AccountRequest {
string account_id = 1;
}
message Transaction {
string txn_id = 1;
string amount = 2;
string type = 3;
}
package com.bank.client;
import com.bank.grpc.AccountServiceGrpc;
import com.bank.grpc.BalanceRequest;
import com.bank.grpc.BalanceResponse;
import io.grpc.ManagedChannel;
import java.math.BigDecimal;
public class GrpcBalanceClient {
private final AccountServiceGrpc.AccountServiceBlockingStub stub;
public GrpcBalanceClient(ManagedChannel channel) {
this.stub = AccountServiceGrpc.newBlockingStub(channel);
}
public BigDecimal getBalance(String accountId) {
BalanceResponse response = stub.getBalance(
BalanceRequest.newBuilder()
.setAccountId(accountId)
.build());
return new BigDecimal(response.getBalance());
}
}
// gRPC call for SAV2001:
// Request: ~12 bytes (binary protobuf)
// Response: ~18 bytes (binary protobuf)
// Latency: ~2ms (HTTP/2 multiplexed connection)
What is Kafka?
Kafka is a fundamentally different model. It is an asynchronous, durable, partitioned log. Producers publish to a topic and return immediately. Messages are persisted and ordered within a partition. Consumer groups read at their own pace, so many independent consumers can process the same stream without affecting each other.
package com.bank.producer;
import com.bank.event.PaymentEvent;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Service
public class PaymentEventProducer {
private final KafkaTemplate<String, PaymentEvent> kafkaTemplate;
public PaymentEventProducer(KafkaTemplate<String, PaymentEvent> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
public void publishPaymentCompleted(String accountId, BigDecimal amount) {
PaymentEvent event = new PaymentEvent(
"PAY-" + System.currentTimeMillis(),
accountId, amount, "COMPLETED");
// Fire and forget: returns immediately
kafkaTemplate.send("payment-events", accountId, event);
}
}
// Producer publishes to topic "payment-events" keyed by SAV2001
// Returns in ~2ms
// Consumer group "notification": reads and sends SMS
// Consumer group "fraud": reads and scores the transaction
// Consumer group "analytics": reads and updates the dashboard
// If fraud consumer is down, messages wait in the partition
How are REST, gRPC, and Kafka different? (comparison table)
The three technologies differ across several axes. REST and gRPC are both synchronous and request-response, while Kafka is asynchronous and publish-subscribe.
| Aspect | REST | gRPC | Kafka |
|---|---|---|---|
| Model | Request-response | Request-response | Publish-subscribe |
| Transport | HTTP/1.1 | HTTP/2 | Custom TCP protocol |
| Encoding | Text (JSON) | Binary (protobuf) | Configurable (Avro, JSON, protobuf) |
| Contract | OpenAPI (optional) | .proto file (required) | Schema Registry (recommended) |
| Coupling | Temporal | Temporal | Decoupled in time |
| Streaming | Not native | Bidirectional | Consumer reads at own pace |
| Browser support | Native | Needs grpc-web proxy | Not applicable |
| Payload size | Larger (text) | Smaller (binary) | Configurable |
| Typical use | Public APIs, simple internal | High-throughput internal | Events, fan-out, pipelines |
When should you use each technology?
Use REST at the public edge for browser and mobile clients. Use gRPC for hot internal paths where latency and payload size matter. Use Kafka for events, fan-out, and high-throughput pipelines. A single transfer at National Bank of India can use all three.
package com.bank.service;
import java.math.BigDecimal;
public class TransferFlow {
// REST: mobile app calls the gateway
// POST /api/v1/transfers {from: "SAV2001", to: "SAV3002", amount: 50000}
// gRPC: gateway calls Account Service internally (fast, typed)
// accountStub.debit(DebitRequest{accountId: "SAV2001", amount: "50000"})
// Kafka: after success, publish event for fan-out
// kafkaTemplate.send("transfer-events", "SAV2001", event)
// REST → universality (browser/mobile)
// gRPC → speed (internal, millions of calls/day)
// Kafka → decoupling (notification, fraud, audit react independently)
}
What are the limitations of each?
REST has larger payloads because JSON is text, no built-in streaming, and HTTP/1.1 overhead. gRPC has poor native browser support, binary payloads that are harder to debug by eye, and requires sharing and regenerating .proto contracts. Kafka has eventual consistency, no synchronous reply, at-least-once delivery that forces idempotent consumers, and harder end-to-end tracing.
// REST limitation: large JSON payload for batch operations
// GET /api/v1/accounts/SAV2001/transactions?limit=1000
// Response: ~500KB of JSON text
// gRPC advantage: same data in protobuf ~150KB (binary, no field names)
// Kafka limitation: no synchronous reply
// WRONG: publish request to Kafka, poll for reply
// CORRECT: use REST or gRPC for synchronous answers
What are common mistakes? (wrong vs correct)
The most common mistake is standardizing on one technology for everything instead of choosing per interaction.
// WRONG: using REST for everything, including high-frequency internal calls
// Account Service calls Fraud Service 50,000 times/second over REST
// Each call: ~45 bytes JSON, HTTP/1.1 overhead, new connection
// Total overhead: massive
// CORRECT: use gRPC for that internal path
// Each call: ~12 bytes protobuf, HTTP/2 multiplexed
// Same data, fraction of the cost
// WRONG: using Kafka for a balance query
// Publish to "balance-request" topic, poll "balance-response" topic
// Slow, fragile, misuses an event log as a request-response channel
// CORRECT: use REST or gRPC for queries
// BigDecimal balance = accountStub.getBalance(request);
What should a senior engineer know?
A senior engineer knows these technologies are complementary, not competing. They choose per interaction rather than standardizing on one. They understand that gRPC's contract-first approach catches mismatches at compile time, which is valuable for internal APIs that change frequently. They also know that Kafka's partitioned log gives ordering within a partition, so keying by account ID guarantees per-account ordering.
// Senior pattern: layered communication
// Layer 1: REST at the public edge (universality)
// Layer 2: gRPC between internal services (speed, typing)
// Layer 3: Kafka as the event backbone (decoupling, replay)
// Key Kafka messages by aggregate ID for ordering
kafkaTemplate.send("payment-events", "SAV2001", event);
// All events for SAV2001 land on the same partition → consumed in order
Visual Overview
REST (HTTP/1.1 + JSON)
──────────────────────
Client ───HTTP/1.1───▶ Server
◀──── JSON ────
Text, human-readable, universal
gRPC (HTTP/2 + Protobuf)
────────────────────────
Client ═══HTTP/2═══▶ Server
◀══ binary ══
Compact, typed, multiplexed, streaming
Kafka (Async Event Log)
───────────────────────
Producer ──▶ Topic [P0][P1][P2] ──▶ Consumer Group A
──▶ Consumer Group B
──▶ Consumer Group C
Durable, ordered per partition, decoupled
Banking Transfer: All Three Together
────────────────────────────────────
Mobile App API Gateway
│ │
│── REST (JSON) ──────────────▶│
│ │── gRPC (protobuf) ──▶ Account Svc
│ │◀── balance ─────────│
│ │── gRPC (protobuf) ──▶ Account Svc
│ │◀── debit ok ────────│
│◀── 200 OK (JSON) ───────────│
│ │── Kafka event ──────▶ [payment-events]
│ │ │ │ │
│ │ Notify Fraud Audit
Key Takeaway
REST, gRPC, and Kafka are three complementary communication technologies, and the right approach is to choose per interaction rather than standardize on one. REST is synchronous request-response over HTTP/1.1 using JSON. It is resource-oriented, human-readable, and universally supported, which makes it the default at the public edge for browsers and mobile apps. gRPC is also synchronous but uses HTTP/2 and binary protocol buffers with a strict .proto contract, giving much smaller payloads, compile-time safety, and bidirectional streaming, which makes it ideal for hot internal service-to-service paths.
Kafka is a completely different model: an asynchronous, durable, partitioned event log. Producers publish to a topic and move on, and many consumer groups read at their own pace. This gives decoupling, buffering under load, replay, and resilience because a down consumer never fails the producer. The cost is eventual consistency and the need for idempotent consumers.
At National Bank of India, Pankaj's transfer flow uses all three. The mobile app speaks REST because it needs a universal protocol. The gateway calls the Account Service over gRPC because that internal hop happens millions of times a day and must be fast and typed. After the transfer succeeds, a PaymentCompleted event is published to Kafka so the notification, audit, and fraud services react asynchronously. This layered approach gives universality at the edge, speed internally, and decoupled fan-out for side effects.
Remember one sentence: use REST for reach at the public edge, gRPC for speed on hot internal paths, and Kafka for decoupled, replayable event fan-out, and never standardize on one technology for all interactions.
---