---
title: "Event-Driven Architecture for PWA"
description: "Why server-sent events and an event-driven model can suit mobile offline-first PWAs better than request-response APIs."
date: 2021-12-30
---

When exploring [Server-Sent
Events](https://en.wikipedia.org/wiki/Server-sent_events), sooner or
later one reaches [Event-Driven
Architecture](https://en.wikipedia.org/wiki/Event-driven_architecture)
(EDA). In fact, EDA is native to web applications. We use it almost
without noticing whenever we put JavaScript behavior into HTML:

``` html
<button onclick="myFunction()">Click me</button>
```

Browser and user interaction is event-based, so event-driven thinking is
intuitive to almost every web developer.

Browser-server interaction is equally familiar: the browser sends a
request and receives the result of the requested action.

<zoom-img src="/medium/img/d77d10cc3276/image-01.png" alt="Basic HTTP request-response interaction" width="100%"></zoom-img>

That is the essence of HTTP: send a request, receive a result.

In 2004, [Ian Hickson](https://en.wikipedia.org/wiki/Ian_Hickson)
proposed [stretching the server response over
time](http://ln.hixie.ch/?count=1&start=1083167110), creating a stream
and processing its result in parts as information arrives. That idea
became the Web API called Server-Sent Events.

<zoom-img src="/medium/img/d77d10cc3276/image-02.png" alt="Server-sent events stream" width="100%"></zoom-img>

The server can now stream information to the client and reflect
processes taking place on the server. Seen through EDA, the server is an
event producer, the browser is a subscriber, and the HTTP connection
plus code at both ends is the event-processing mechanism or queue.

This design requires asynchronous data handling and resilience to losing
individual events. It naturally suggests a return stream of browser
requests confirming that corresponding server events were received.

<zoom-img src="/medium/img/d77d10cc3276/image-03.png" alt="Event confirmation over HTTP" width="100%"></zoom-img>

A browser can send receipt confirmations with ordinary POST requests to
one service for all events, including the event ID. But confirmation
alone does not solve delivery loss: the confirmation can also disappear.
The application must tolerate a lost message. If an expected reaction
does not occur within an acceptable interval, it sends the event again;
subscribers decide whether they already handled it or missed it.

The more interesting step is to treat that confirmation channel as an
inverted SSE stream and send browser-to-server messages asynchronously
too. Rather than many synchronous web services for different actions,
the application has two channels: a forward channel receiving messages
from the browser and a return channel sending server events to the
browser.

<zoom-img src="/medium/img/d77d10cc3276/image-04.png" alt="Two event channels between browser and server" width="100%"></zoom-img>

This model suits mobile PWAs that must work offline. They keep working
data on the client in `localStorage` or `indexedDb` and exchange data
with the server whenever possible. The entire Web API can then be
reduced to two services: open the server-event channel and report a
browser event to the server.

For applications built this way, synchronous request-response
technologies such as REST, GraphQL, and gRPC become less central. I do
not claim that EDA replaces them. For mobile PWAs that repeatedly move
between offline and online states, event streams can fit better; for
ordinary web applications with stable internet, established
request-response technologies remain more predictable.
