Realtime
Snaapi supports realtime event streaming via Server-Sent Events (SSE). Connect to the stream endpoint to receive filtered, permission-aware events as they happen.
SSE Streaming
Server-Sent Events provide a one-way, persistent connection from the server to
the client. Events are streamed over HTTP with automatic reconnection support
built into the browser's EventSource API.
Response Headers
| Header | Value |
|---|---|
Content-Type |
text/event-stream |
Cache-Control |
no-cache |
Connection |
keep-alive |
X-Accel-Buffering |
no |
Stream Endpoint
GET /stream/{resourceName}
Requires authentication. The authenticated user's permissions determine which events and fields are visible.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
events |
string |
created,updated,deleted |
Comma-separated event types to subscribe to |
fields |
string |
All allowed fields | Comma-separated field names to include |
Examples
Subscribe to all events for a resource:
GET /stream/posts
Subscribe to only created and updated events:
GET /stream/posts?events=created,updated
Subscribe with specific fields:
GET /stream/posts?events=created&fields=title,author_id
Event Filtering
Event Type Filtering
Use the events query parameter to subscribe to specific event types. Valid
values are created, updated, and deleted.
Field Filtering
Use the fields query parameter to limit which fields appear in the event data.
The following rules apply:
- Requested fields are intersected with the user's allowed fields (from permissions)
- System fields (
id,created_at,updated_at) are always included - The
changesarrays in event data are updated to reflect only filtered fields
Permission-Based Filtering
Events are filtered based on the authenticated user's read permissions:
- Only events matching the user's filter constraints are delivered
- Only fields the user has permission to read are included
- Filter operators applied:
eq,neq,in,nin,gt,gte,lt,lte,is_null,is_not_null,like,ilike,regex,iregex,similar
Connection Lifecycle
1. Connection Established
The client connects with authentication credentials. On success, the server sends an initial message:
retry: 3000
: connected
The retry: 3000 directive tells the client to wait 3 seconds before attempting
to reconnect if the connection drops.
2. Heartbeat
The server sends a heartbeat comment every 30 seconds to keep the connection alive and detect disconnects:
: heartbeat
3. Event Delivery
When a matching event occurs, it is streamed in SSE format:
event: posts.created
data: {"old":null,"new":{"id":"abc-123","title":"Hello"},"changes":{"added":["id","title"],"updated":[],"removed":[]}}
id: event-uuid
retry: 3000
| SSE Field | Description |
|---|---|
event |
Event type (e.g., posts.created) |
data |
JSON-encoded event data (old/new/changes) |
id |
Event UUID (used for reconnection resumption) |
retry |
Reconnection delay in milliseconds |
4. Disconnection
When the client disconnects (network drop, tab close, explicit close):
- The server detects the disconnection
- The connection is unsubscribed from the
EventBroadcaster - Resources are cleaned up automatically
Client Example
const eventSource = new EventSource("/stream/posts", {
headers: { Authorization: "Bearer <token>" },
});
eventSource.addEventListener("posts.created", (event) => {
const data = JSON.parse(event.data);
console.log("New post:", data.new);
});
eventSource.addEventListener("posts.updated", (event) => {
const data = JSON.parse(event.data);
console.log("Updated:", data.changes.updated);
});
eventSource.onerror = () => {
console.log("Connection lost, reconnecting...");
};