Skip to content

Microservices Communication: Where Each Protocol Belongs

Core Concept LearningJuly 2, 20265 min readUpdated July 21, 2026

A checkout call may hit REST at the gateway, a GraphQL BFF for the mobile screen, gRPC between order and inventory, and a webhook when the payment provider settles. Failures usually come from using one protocol in the wrong layer—not from picking the “wrong brand.”

This article is a placement map: who speaks at the edge, what the gateway owns, what stays internal, and what wraps legacy. For style mechanisms (REST vs GraphQL vs gRPC), see API Styles: REST vs GraphQL vs gRPC. For push timelines (polling → SSE → WebSocket), see 4 Ways to Get Real-Time Updates.

Client, gateway, and backend protocol layers
Client, gateway, and backend protocol layers

Layers: edge, gateway, internal, integration

Treat protocols as roles on a path, not a single menu. Edge: browsers and mobile use REST, GraphQL, or WebSockets. Gateway: one public front door for HTTP—routing, TLS, auth, rate limits (see NGINX Gateway). Internal: service-to-service calls prefer typed RPC (gRPC) when both ends are yours. Integration: partners push via webhooks; ancient systems may still demand SOAP behind an adapter.

No single protocol owns every hop. The diagram under the intro is the map; the sections below only place each option and point you to the deep guide when you need mechanisms or code.

Quick reference

  • Edge — REST / GraphQL / WebSocket for diverse clients.
  • Gateway — centralize auth, TLS, routing, limits before apps.
  • Internal — gRPC (or plain HTTP) between owned services.
  • Integration — webhooks in; SOAP only behind an anti-corruption adapter.
  • Async work — queues and streams are a different axis; see Kafka vs RabbitMQ vs SQS.

Remember this

Naming the boundary first — edge, gateway, internal, integration — fixes most of the protocol choice before REST/GraphQL/gRPC even enters the conversation.

REST at the gateway (client front door)

REST stays the default client-facing contract: resource URLs, HTTP verbs, JSON. Clients should talk to one gateway host—not every internal service name. The gateway routes /orders to the order service while keeping topology private.

Placement rule: expose REST (or GraphQL) at the edge; do not make browsers discover orders.internal. Style depth, caching, and over-fetch trade-offs live in the REST vs GraphQL vs gRPC guide. Edge timeouts and proxy_pass live in the NGINX guide.

REST through the API Gateway
REST through the API Gateway

Quick reference

  • Place REST on the public/partner HTTP boundary.
  • Gateway owns auth, TLS, routing, and rate limits once.
  • Version the public URL so internals can move independently.
  • When not: pure internal fan-out at high QPS — prefer gRPC mesh hops.
Client knows every internal host
1// Fragile: three hosts, three failure modes2const user = await fetch("https://users.internal/api/me");3const orders = await fetch("https://orders.internal/api/mine");4if (!user.ok || !orders.ok) throw new Error("partial edge failure");
Client talks to one gateway
1// One front door; gateway routes internally2const res = await fetch("https://api.example.com/v1/me/orders", {3  headers: { Authorization: `Bearer ${token}` },4  signal: AbortSignal.timeout(5_000),5});6if (res.status === 429) {7  // Edge rate limit — back off; do not hammer upstreams8  throw new Error(`rate limited; retry after ${res.headers.get("Retry-After")}`);9}10if (!res.ok) throw new Error(`gateway ${res.status}`);11const orders = await res.json();

Remember this

REST belongs at the client-facing gateway, not as the default internal mesh language.

GraphQL beside the gateway (shaped client reads)

GraphQL sits next to or behind the same edge policy: one query endpoint, many field shapes. Use it when web and mobile need different slices of the same product graph—not because it replaces REST everywhere.

Placement: public or BFF tier. Resolvers then call internal REST or gRPC. Query depth limits, N+1, and caching trade-offs are covered in API Styles—this page only parks GraphQL on the edge map.

GraphQL query through the gateway
GraphQL query through the gateway

Quick reference

  • Place GraphQL where clients need shaped reads in one round trip.
  • Keep auth and limits on the gateway/BFF in front of resolvers.
  • When not: simple CRUD with one client type — REST is enough.
  • Defer schema, DataLoader, and error-extension patterns to the style guide.

Remember this

GraphQL is an edge/BFF read shape—not an internal service bus.

WebSockets for live push (often past the REST gateway)

Persistent duplex sockets often bypass the plain REST gateway path and land on a dedicated realtime service (still behind TLS and an upgrade-aware proxy). Use them when both sides must speak on the same channel—chat, collab cursors, trading UIs.

For one-way server push, prefer SSE. Timelines, reconnect, and when polling is enough are in WebSocket vs SSE vs long polling—do not treat this overview as a realtime how-to.

WebSocket bypasses the gateway
WebSocket bypasses the gateway

Quick reference

  • Place WebSocket on a sticky or pub/sub-backed realtime tier.
  • Proxy must pass Upgrade headers and long idle timeouts.
  • When not: notifications and progress bars — SSE is simpler.
  • Async fan-out behind the socket service may still use Kafka/queues.

Remember this

WebSockets are a delivery lane for duplex live traffic—not a substitute for REST CRUD.

Webhooks: external systems push in

Webhooks reverse the caller: a partner POSTs to your URL when something happens. That endpoint is an integration surface—verify signatures, answer fast, and hand work to a queue. Heavy work on the request thread causes partner retries and duplicate events.

Placement: public HTTPS callback → verify → enqueue → 200. Broker choice for the queue is separate (Kafka vs RabbitMQ vs SQS).

Webhook from external system
Webhook from external system

Quick reference

  • Place webhooks on a dedicated public path with signature checks.
  • Respond quickly; process via queue; handlers must be idempotent.
  • When not: you control both sides and can share a private stream instead.
Polling the partner (wasteful)
1// Fragile: empty polls + missed windows2setInterval(async () => {3  const res = await fetch("https://partner.example/events");4  if (!res.ok) return; // silent miss5  await processEvents(await res.json());6}, 30_000);
Webhook: verify, enqueue, ack fast
1app.post("/webhooks/partner", async (req, res) => {2  if (!verifySignature(req)) {3    return res.status(401).send("invalid signature");4  }5  try {6    await queue.publish("partner.event", req.body); // durable hand-off7    res.status(200).send("OK");8  } catch {9    // Partner will retry — do not 200 if you dropped the event10    res.status(503).send("try again");11  }12});

Remember this

Webhooks are inbound integration HTTP—verify, enqueue, then work.

gRPC inside the backend boundary

Inside the mesh, services often call each other with gRPC (Protobuf over HTTP/2): typed stubs, streaming options, no browser contract. Keep it behind the gateway—clients still see REST/GraphQL.

Placement: Service A → Service B → Service S on private networks. Contracts, streaming modes, and browser limits are in API Styles.

Internal gRPC between services
Internal gRPC between services

Quick reference

  • Place gRPC on owned service-to-service hops.
  • Generate stubs from .proto; fail at compile time, not JSON surprise.
  • When not: one internal CRUD hop and no shared protobuf toolchain — HTTP JSON is fine to start.
  • Never expose raw gRPC to browsers without a deliberate gRPC-Web proxy.
gRPCProtocol BuffersHTTP/2grpcurlEnvoy

Remember this

gRPC is the internal highway—typed and fast, hidden from public clients.

SOAP only as a legacy adapter

SOAP/XML still appears where contracts already mandate it (older ERP, government, industry rails). Do not spread XML through your domain. Put an anti-corruption service in front: clean internal API in, SOAP out.

Placement: last-resort integration hop—not a peer of REST/GraphQL for greenfield public APIs. Audience vs style axes are spelled out in Types of APIs.

SOAP for legacy integration
SOAP for legacy integration

Quick reference

  • Place SOAP behind one adapter service.
  • Generate clients from WSDL; never hand-roll envelopes in domain code.
  • When not: you control both ends — prefer REST/OpenAPI or gRPC.

Remember this

SOAP is a legacy boundary to wrap—not a default modern edge protocol.

Decision rule by boundary

Ask who is calling and which hop you are on. Browser/mobile CRUD → REST via gateway. Many client shapes → GraphQL at the BFF. Live duplex → WebSocket (else SSE). Partner event → webhook. Owned service mesh → gRPC. Mandated XML → SOAP adapter. Background work → a broker, not another sync protocol.

One reason internal hops favor gRPC: its deadlines propagate down the call chain. A gateway can give a request a 300ms budget, hand the inner gRPC call a 250ms deadline, and let DEADLINE_EXCEEDED fail fast with no retry budget left — instead of a slow hop silently eating the whole request.

If two guides seem to overlap, use this page for where, the style guide for how REST/GraphQL/gRPC differ, and the realtime guide for how push is delivered.

One internal RPC: deadline expires, retry budget blocks a retry storm
One internal RPC: deadline expires, retry budget blocks a retry storm

Quick reference

  • Edge CRUD → REST + gateway.
  • Shaped multi-client reads → GraphQL BFF.
  • Duplex live → WebSocket; one-way push → SSE (realtime guide).
  • External notify-you → webhook + queue.
  • Internal typed hops → gRPC.
  • Legacy XML mandate → SOAP adapter only.

Remember this

Protocol follows the boundary—edge, gateway, internal, integration—not preference.

Key takeaway

Production backends are protocol sandwiches: REST/GraphQL at the edge, upgrade-aware realtime beside them, webhooks inbound, gRPC inside, SOAP only as an adapter. Start with REST through a gateway; add the next protocol when a boundary forces it.

Practice (15 min): Pick one user action (e.g. “place order”). Draw four boxes—Client, Gateway, Order service, Payment partner—and label one protocol on each arrow. Then open the style or realtime guide for the hop you are least sure about and write one sentence on when that hop should not use your first choice.

Share:

Related Articles

Selecting the communication protocol between clients, API gateways, and internal microservices impacts API latency, payl

Read

Your mobile team wants one round trip for a screen. Your partner wants a stable URL they can cache. Your services need t

Read

A travel checkout may call a public weather API, your own booking API, and a partner airline API. All three could use RE

Read

Keep learning

Follow a structured path or browse all courses to go deeper.