Request/Response

Request/Response is a synchronous communication style where the client sends a request and waits for an immediate response from the service. Typical examples include HTTP REST (the most common web API style), gRPC (Google's high-performance binary protocol used in microservices), and SOAP (a legacy XML-based protocol still found in enterprise systems). This approach is the simplest and most predictable, ideal for scenarios where an immediate result is required before the caller can proceed.

✅ When is it appropriate

Request/Response is suitable if most of the following apply:

  • you need immediate responses and low latency
  • orchestration between services is simple
  • the number of service-to-service calls is small
  • consistency and transactions are critical
  • the team has experience with synchronous approaches

In these cases, Request/Response is a simple and reliable solution.

❌ When is it NOT appropriate

Request/Response may not be ideal if:

  • the number of service-to-service calls is high or payloads are large
  • the system must be highly resilient and scalable
  • orchestration between services is complex
  • an event-driven architecture would be more suitable
  • downstream services are frequently slow or unavailable, because every outage directly blocks and fails the callers waiting for a response

When many services call each other synchronously in a chain, a slowdown or failure in any one of them blocks all the callers waiting upstream. This creates bottlenecks where a single slow service degrades the response time of the entire system, and a single unavailable service causes cascading failures across all services that depend on it.

👍 Advantages

  • simple and predictable calls
  • immediate response and error handling
  • easy debugging and logging
  • supports transactional consistency
  • straightforward flow tracking between services

👎 Disadvantages

  • the client is tightly dependent on service availability: if the service is down or too slow, the client's request fails immediately because there is no buffer or retry mechanism built into synchronous calls
  • latency issues with a high number of calls
  • less flexible for distributed systems
  • more complex scalability as the number of services grows
  • susceptible to cascading failures: if a called service is slow or crashes, the calling service is blocked and may also become unresponsive, spreading the failure upward through the system

🛠️ Typical use cases

  • CRUD APIs between the client and backend
  • short and fast transactional operations
  • integrations with external synchronous systems
  • simple microservices architectures
  • services where an immediate response is critical

⚠️ Common mistakes (anti-patterns)

  • excessive service-to-service calls within a single transaction
  • ignoring timeouts and fallback mechanisms
  • attempting to process large amounts of data at once
  • poor documentation and orchestration of flow
  • combining with event-driven approaches without a clear design

When a single request triggers a chain of synchronous calls across multiple services and no timeouts are configured, a slow response anywhere in the chain can cause the original request to hang indefinitely. Over time, these hanging requests consume all available threads or connections, which causes the entire application to stop responding, even for unrelated operations.

💡 How to build on it wisely

Recommended approach:

  1. Use it where an immediate response is required.
  2. Minimize the number of service-to-service calls.
  3. Implement timeouts (a maximum wait time for a response) and fallback mechanisms (a predefined action to take when a service fails, such as returning a cached result or a default value instead of propagating the error).
  4. Monitor latency and failures.
  5. Combine with event-driven approaches where appropriate.

Request/Response is a solid default choice for straightforward interactions where the caller needs an immediate result. Its main risk is tight coupling between services, so the most important safeguards are short call chains, enforced timeouts, and a clear plan for what happens when a dependency is unavailable.

Feedback & Sharing

Give us your thoughts on this page, or share it with others who may find it useful.

Share with your network:

Feedback

Found this helpful? Let me know what you think or suggest improvements 👉 Contact me.