Skip to content

Observing Events

This guide shows how to observe events in EventSourcingDB using its HTTP API. You'll learn how to subscribe to live events as well as how to replay historic events if needed.

Observing Events for a Single Subject

Just like reading events, observing events for a single subject is the simplest possible approach.

Apart from using the /api/v1/observe-events endpoint instead of /api/v1/read-events, the request is conceptually the same:

curl \
  -i \
  -X POST \
  -H "authorization: Bearer <API_TOKEN>" \
  -H "content-type: application/json" \
  -d "{
    \"subject\": \"/books/42\",
    \"options\": {
      \"recursive\": false
    }
  }" \
  http://localhost:3000/api/v1/observe-events

If everything worked as expected, the server will respond with HTTP status code 200 OK:

HTTP/1.1 200 OK

As with reading, the response body initially contains all previously stored events in NDJSON format – but the difference is what happens next: While reading ends after all events have been returned, observing keeps the connection open.

To prevent intermediate proxies or other network components from closing the connection due to inactivity, periodic heartbeat entries are sent:

{ "type": "heartbeat", "payload": {}}

Whenever a new event is written via another connection, it will be streamed through this endpoint as well.

This allows clients to subscribe to a subject and get notified about new events as soon as they happen.

Observing Events for Multiple or All Subjects

To observe events for multiple subjects at once, you can – just like when reading – choose an appropriate base subject and set the recursive parameter to true.

The following request shows how to observe all events stored in the database. In addition to the recursive flag, it is important to specify the root subject /:

curl \
  -i \
  -X POST \
  -H "authorization: Bearer <API_TOKEN>" \
  -H "content-type: application/json" \
  -d "{
    \"subject\": \"/\",
    \"options\": {
      \"recursive\": true
    }
  }" \
  http://localhost:3000/api/v1/observe-events

Resuming After Connection Loss

If a client gets disconnected from the database, it can reconnect at any time. It will first receive all existing events again, followed by live updates.

If the client remembers the ID of the last event it received, it can resume from that exact point by setting the lowerBound parameter. For example, if the last received event had ID 2010, the client can use the following request to proceed from the event following the given one:

curl \
  -i \
  -X POST \
  -H "authorization: Bearer <API_TOKEN>" \
  -H "content-type: application/json" \
  -d "{
    \"subject\": \"/\",
    \"options\": {
      \"recursive\": true,
      \"lowerBound\": {
        \"id\": \"2010\",
        \"type\": \"exclusive\"
      }
    }
  }" \
  http://localhost:3000/api/v1/observe-events

This ensures that no events are lost even if the connection is temporarily unavailable.

Observing From the Last Event of a Given Type

Also similar to reading, you can start observing from the last occurrence of a specific event type using the fromLatestEvent parameter. For example, to observe all events that happen after a book was last borrowed, use this command:

curl \
  -i \
  -X POST \
  -H "authorization: Bearer <API_TOKEN>" \
  -H "content-type: application/json" \
  -d "{
    \"subject\": \"/books/42\",
    \"options\": {
      \"recursive\": true,
      \"fromLatestEvent\": {
        \"subject\": \"/books/42\",
        \"type\": \"io.eventsourcingdb.library.book-borrowed\",
        \"ifEventIsMissing\": \"wait-for-event\"
      }
    }
  }" \
  http://localhost:3000/api/v1/observe-events

The ifEventIsMissing parameter controls what should happen if no matching event is found:

  • If set to read-everything, all events for the given subject will be read.
  • If set to wait-for-event, the request will wait until a matching event occurs, and then begin observing.

This also means that if you specify a non-existent subject, you won't get an error. Instead, the behavior depends on the value of the ifEventIsMissing parameter.

Incompatible Parameters

You cannot combine fromLatestEvent with lowerBound.

Your Turn

Now that you know how to write, read, and observe events, try combining them – write events and attach one or more observers at the same time.

Here are some ideas:

  • Observe all events for a book that does not exist yet, then create the book.
  • Observe all events for all readers.
  • Observe all events across all books and readers, disconnect in between, then reconnect using the ID of the last received event to resume.