SSE API Overview
RESTHeart Cloud|
Note
|
SSE support is available from RESTHeart 9.4 onwards. |
Server-Sent Events (SSE) is a W3C standard for pushing real-time updates from a server to a browser or HTTP client over a plain HTTP connection. Unlike WebSockets, SSE is unidirectional — data flows only from server to client — which makes it simpler to implement, firewall-friendly, and natively supported by all modern browsers via the EventSource API.
Server-Sent Events (SSE) is a server push technology enabling a client to receive automatic updates from a server over an HTTP connection.
Two SSE Use Cases in RESTHeart
RESTHeart supports SSE in two complementary ways:
1. MongoDB Change Streams over SSE
Any MongoDB change stream defined on a collection can be consumed via SSE by sending a request with the Accept: text/event-stream header instead of a WebSocket upgrade. No plugin code is required.
Change stream definitions (the streams metadata, aggregation stages, and the notify_when per-client filter) are managed on the collection — see Change Streams.
# Connect to a change stream via SSE
curl -N \
-H 'Accept: text/event-stream' \
-H 'Authorization: Basic YWRtaW46c2VjcmV0' \
http://localhost:8080/messages/_streams/all
Events arrive as soon as documents are inserted, updated, or deleted in the collection:
event:change
data:{"fullDocument":{"_id":{"$oid":"..."},"message":"Hello!"},"operationType":"insert"}
event:change
data:{"documentKey":{"_id":{"$oid":"..."}},"operationType":"delete"}
This mode requires MongoDB configured as a Replica Set. See Change Streams over SSE Tutorial for a full walkthrough.
2. Custom SseService Plugins
For use cases that don’t involve MongoDB — live dashboards, system metrics, log tailing, IoT feeds — RESTHeart provides the SseService plugin interface. Implement it, annotate the class with @RegisterPlugin, and the framework wires the SSE endpoint automatically.
@RegisterPlugin(name = "clockSse", description = "UTC clock feed", defaultURI = "/sse/clock")
public class ClockSseService implements SseService {
@Override
public void onConnect(ServerSentEventConnection conn, String lastEventId) {
conn.setKeepAliveTime(15_000);
Thread.ofVirtual().start(() -> {
try {
while (conn.isOpen()) {
conn.send(Instant.now().toString(), "tick", null, null);
Thread.sleep(Duration.ofSeconds(1));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
}
This mode works in standalone mode (-s flag) — no MongoDB connection is required. See Custom SseService Plugin for a complete guide.
Permissions Apply to a Stream
A change stream is a read, and the caller’s permission governs it as it governs the equivalent GET. Since 9.8.2:
-
the
readFilterof the matching permission is applied to the events: a caller limited to their own documents is notified about their own documents only, and events that carry no document — deletes — are not delivered when the filter is about the document’s own fields; -
an exclusion
projectResponseremoves those properties from the event, including fromupdateDescription.updatedFields; -
a
readFilterthat cannot be applied to an event ($expr,$where,$text) and an inclusionprojectResponse, which would strip the event’s resume token, refuse the subscription with403.
|
Warning
|
Before 9.8.2 neither was applied. A caller who could open the stream received every event on the collection, whatever their readFilter, and with the properties projectResponse hides. If you run an older version, restrict who may reach /_streams until you upgrade.
|
Filtering per client with notify_when is a convenience for the client, not a boundary: the variable it binds comes from the client’s own query string. See notify_when.
SSE vs. WebSocket
Both SSE and WebSocket expose MongoDB change streams at the same URL path (/_streams/<name>). Choose based on your client requirements:
| Feature | SSE | WebSocket |
|---|---|---|
Direction |
Server → client only |
Full-duplex (bidirectional) |
Protocol |
Plain HTTP/1.1 or HTTP/2 |
HTTP upgrade to |
Browser API |
|
|
Auto-reconnect |
Native ( |
Must be implemented by the client |
Resume from last event |
|
No built-in resume protocol |
Firewall / proxy compatibility |
Excellent — travels over port 80/443 as HTTP |
May require proxy configuration |
RESTHeart URL |
|
|
|
Note
|
Both transports share the same MongoDB cursor via ChangeStreamWorker. A single cursor fans out to all WebSocket and SSE clients subscribed to the same stream, regardless of the transport they use.
|
SSE Event Format
Each change event sent over SSE contains three non-blank lines:
id:<resume-token-json>
event:change
data:<json-payload>
The id field is the MongoDB resume token serialised as JSON. Browsers and SSE clients automatically send it back as Last-Event-ID on reconnect, allowing RESTHeart to resume the stream from the correct position (when notify_when is not defined — see notify_when).
The data field contains the same JSON structure as a WebSocket change event:
{
"fullDocument": {
"_id": { "$oid": "..." },
"message": "Hello!",
"name": "uji"
},
"documentKey": {
"_id": { "$oid": "..." }
},
"updateDescription": null,
"operationType": "insert"
}
|
Tip
|
The event: field value (change) allows the browser EventSource API to route events with es.addEventListener('change', handler) instead of the generic es.onmessage.
|
Requirements
-
MongoDB Change Streams over SSE — MongoDB must be configured as a Replica Set.
-
Custom SseService plugins — No MongoDB required; works in standalone mode (
java -jar restheart.jar -s).
Next Steps
-
Tutorial: MongoDB Change Streams over SSE — step-by-step guide to streaming MongoDB change events to HTTP clients
-
Custom SseService Plugin — build your own SSE endpoint without MongoDB
-
WebSocket API Overview — the full-duplex alternative for change streams