Event-Driven Architecture vs. REST: When to Use Which
In modern backend engineering, the debate between synchronous REST APIs and asynchronous Event-Driven Architecture (EDA) is constant.
Developers often fall into two camps: those who try to solve every problem with a synchronous HTTP call, and those who introduce Apache Kafka into a system that only has three users.
The reality is that production systems need both. The secret isn’t choosing one over the other; it’s knowing exactly when to use which.
REST: The Synchronous Standard
REST over HTTP is synchronous (at the architectural level, regardless of non-blocking IO under the hood). When Service A calls Service B, Service A waits for a response.
When to Use REST
1. Immediate Consistency is Required. If a user is checking their bank account balance, they need the exact, up-to-the-millisecond number. You cannot serve this data from an eventually consistent read model that might be 5 seconds behind. You need a direct, synchronous query to the source of truth.
2. The Client Needs an Immediate Answer. If a user submits a form to change their password, the UI needs to know right now if the old password was correct. Telling the client “We’ve queued your password change for processing” provides a terrible user experience.
3. Simple CRUD Operations. If a service is just a thin wrapper over a database providing basic Create, Read, Update, and Delete operations for administrative purposes, introducing a message broker is massive over-engineering.
The Downside of REST
The biggest problem with REST in microservices is temporal coupling. If Service A needs Service B to complete an action, both services must be alive and healthy at the exact same moment. If Service B is down, Service A fails. Chain this across 5 services, and your system’s availability plummets.
Event-Driven Architecture: The Asynchronous Backbone
In an Event-Driven Architecture, components communicate by emitting and reacting to events (e.g., OrderPlaced, UserRegistered). The producer doesn’t know who is consuming the event, and it doesn’t wait for a response.
When to Use EDA
1. Fire-and-Forget Workflows.
When a user signs up, you might need to send a welcome email, update a CRM, and provision an analytics workspace. The user shouldn’t have to wait 8 seconds for all of this to finish before they see the dashboard. The signup service should just emit a UserRegistered event and return a 200 OK instantly.
2. High Availability is Non-Negotiable.
If your payment processor goes down, your e-commerce site should still be able to accept orders. By placing CheckoutCompleted events onto a message queue, the order service can stay up. When the payment service recovers, it will simply process the backlog of events.
3. Fan-out Scenarios. If you have data that needs to be consumed by multiple distinct downstream systems (e.g., search indexing, analytics data lakes, cache invalidation), emitting a single event for multiple subscribers is significantly cleaner than having the upstream service make 5 separate REST calls.
The Downside of EDA
Event-driven systems are notoriously hard to debug. You lose the linear stack trace. When something goes wrong, you have to piece together logs across distributed systems using correlation IDs.
Furthermore, you have to design for Eventual Consistency. Developers and business stakeholders must accept that data takes time to propagate through the system.
The Hybrid Reality
The most resilient architectures I’ve worked on use a hybrid approach.
- Reads are almost always synchronous REST (or GraphQL/gRPC) calls.
- Critical path writes (where immediate validation is required) are synchronous.
- Side effects and cross-domain state changes are handled asynchronously via events.
Stop treating REST and Events as an either/or choice. Use REST for queries and immediate validation; use Events for decoupled workflows and side-effects.