Writing a Client
What a client of the protocol has to do, whatever its language. The calls themselves are in the HTTP API.
Positions
- Keep the store ID and the Sequence Position together.
- If a read returns another store ID, start over from the beginning.
Reads
- Tell a trailer apart from an event by its shape: a
hasMorekey forQUERY /events, anendkey in a transaction. - Treat a response with no trailer as cut short. Outside a transaction, resume after the last full event. In a transaction, abandon it and run the command again.
- Parse a read line by line, as it arrives.
Transactions
- After a read of events, the next call is the write of events that closes it, with events or an empty list.
- Read a projection in the transaction before you replace or delete it. A
createneeds no read. - Send one call at a time on a transaction.
- After
409 ConcurrencyExceptionor404 TransactionNotFound, run the whole command again, in a new transaction. POST /txcan get503 Paused. What to do with the command is the application’s choice.- Abandon a transaction you no longer need, for example in the error handler around a command, and ignore the response.
- Give each event of a write the
timethe write returned: it’s thetimethe event keeps once committed.
Projections
- Treat a version as opaque: compare it for equality only.
- After
POST /projections, use the version from the response for the next change.
Lost responses
- A commit can’t be sent again. Run the command again, in a new transaction.
- A
POST /projectionscan be sent again as is. On a409, read the projections again.
Testing
- In development mode, empty the store between tests with
POST /pause,POST /reset, thenPOST /resume. testdata/query-cases.jsonlists queries, events, and whether each query selects each event.
How the server works
How the server works inside, and the reasons behind its behavior, are in the Go comments of the
repository. go doc ./... gives the role of each package.