DEV Community

Cover image for Message-Driven architecture vs REST-APIs
Mirza Leka
Mirza Leka

Posted on

Message-Driven architecture vs REST-APIs

A question I often get: "Do you use message-driven architecture just because REST APIs are slow?" - Well… yes, but actually no. There’s much more behind that decision.

Why use Message-Driven architecture

Cross-device support

The messaging systems allow for real-time communication across servers, desktops, web & mobile apps — all decoupled and event-driven.

Asynchronous communication

REST API forces the sender to wait. Messaging lets you offload heavy work to background consumers while the app stays responsive.

Supports monoliths

The producer-consumer architecture can be used within a single service using in-process events.

Multi-destination delivery

With REST APIs, the sender needs to know the exact endpoint of each receiver. Messaging system publishes to a topic — whoever’s subscribed gets the message. No need to know who or where they are.

Retention

REST API fails if the receiving server is down. Messaging brokers store messages until consumers reconnect. With TTL, you can control how long unconsumed messages are retained before they are discarded.

Fault tolerance

Retries and dead‑letter queues are ideal for systems that favor built‑in recovery mechanisms to reduce the need for manual intervention.

But is messaging suitable for every backend?
No. You should also be aware of the drawbacks.

Drawbacks of MDA

Extra complexity

You need to manage brokers, consumers, retry policies, and observability.

Tracking requests is harder

Messages can fan out to multiple destinations. Tracing who picked up what, when, and what happened next is a challenge.

And because messaging is inherently push‑based...

No immediate response

Publishers don't wait for a response; the server can’t guarantee instant feedback to user actions.

Eventual consistency

Messaging systems can always send requests, but the downed services need to catch up later. This is not ideal for systems that require strict transactional processes.

Idempotency

The retry mechanism may redeliver the same message when a consumer fails or times out. The consumers must be idempotent to avoid processing the same request multiple times.
Idempotency doesn't spare REST APIs either.

Every software architecture is a trade‑off. Which direction do you lean into?

If you’re curious to dive deeper into Messaging or Event‑Driven Architecture, I’ve written a handful of articles on the topic.

Top comments (4)

Collapse
 
acytryn profile image
Andre Cytryn

the idempotency point hits different in payment systems. REST can have the same problem, but at least failure modes are obvious. with messaging, a consumer crash mid-processing can leave you with duplicate side effects that are nearly impossible to detect without audit logs. one pattern I've seen work well: storing a processed_message_ids table and checking before committing state changes. adds a small write overhead but makes redelivery safe. have you found a cleaner approach to consumer idempotency?

Collapse
 
mirzaleka profile image
Mirza Leka

I've used the inbox pattern.

  • Set a unique ID (or correlation ID) as the message header

  • Save it into the inbox table after you complete processing

  • If the same ID occurs, automatically acknowledge the message

Collapse
 
mirzaleka profile image
Mirza Leka • Edited

Yes. DB operations are overhead, and what if you cannot insert or update for some reason? If not a table, push it into a different queue (or Kafka topic) and peek to see if the message is already there. Take the latter with a grain of salt.

Collapse
 
mirzaleka profile image
Mirza Leka

Or enforce exactly once delivery by always acknowledging messages on the consumer side. But what happens to messages that are lost? Apply the outbox pattern to the producer. To avoid the dual-write problem, store all messages in a table with unique message IDs and use CDC tools to move newly inserted records to the message broker.