Expected Version

When you append to a stream you often want to use Expected Version to allow for optimistic concurrency with a stream. You commonly use this for a domain object projection.

i.e., "A append operations can succeed if I have seen everyone else's append operations."

You set ExpectedVersion with the syntax ES-ExpectedVersion: #, where # is an integer version number. There are other special values available:

  • 0, the stream should exist but be empty when appending.
  • -1, the stream should not exist when appending.
  • -2, the write should not conflict with anything and should always succeed.
  • -4, the stream or a metadata stream should exist when appending.

If the ExpectedVersion does not match the version of the stream, EventStoreDB returns an HTTP 400 Wrong expected EventNumber response. This response contains the current version of the stream in an ES-CurrentVersion header.

In the following cURL command ExpectedVersion is not set, and it appends or create/append to the stream.

curl -i -d "@event.json" "http://127.0.0.1:2113/streams/newstream" \
    -H "Content-Type:application/vnd.eventstore.events+json"
    -u "admin:changeit"
1
2
3
HTTP/1.1 201 Created
Access-Control-Allow-Methods: POST, DELETE, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Requested-With, X-PINGOTHER
Access-Control-Allow-Origin: *
Location: http://127.0.0.1:2113/streams/newstream/0
Content-Type: text/plain; charset: utf-8
Server: Mono-HTTPAPI/1.0
Date: Fri, 28 Jun 2013 12:17:59 GMT
Content-Length: 0
Keep-Alive: timeout=15,max=100
1
2
3
4
5
6
7
8
9
10

The stream newstream has one event. If you append with an expected version of 3, you receive an error.

curl -i -d @event-version.json "http://127.0.0.1:2113/streams/newstream" \
    -H "Content-Type:application/vnd.eventstore.events+json" \
    -H "ES-ExpectedVersion: 3"
1
2
3
HTTP/1.1 400 Wrong expected EventNumber
Access-Control-Allow-Methods: POST, DELETE, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Requested-With, X-Forwarded-Host, X-Forwarded-Prefix, X-PINGOTHER, Authorization, ES-LongPoll, ES-ExpectedVersion, ES-EventId, ES-EventType, ES-RequiresMaster, ES-HardDelete, ES-ResolveLinkTos
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ES-Position, ES-CurrentVersion
ES-CurrentVersion: 0
Content-Type: text/plain; charset=utf-8
Server: Mono-HTTPAPI/1.0
Date: Tue, 14 Aug 2018 14:08:44 GMT
Content-Length: 0
Connection: close
1
2
3
4
5
6
7
8
9
10
11

You can see from the ES-CurrentVersion header above that the stream is at version 0. Appending with an expected version of 0 works. The expected version is always the version of the last event known in the stream.

curl -i -d @event-version.json "http://127.0.0.1:2113/streams/newstream" \
    -H "Content-Type:application/vnd.eventstore.events+json" \
    -H "ES-CurrentVersion: 0"
1
2
3
HTTP/1.1 201 Created
Access-Control-Allow-Methods: POST, DELETE, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Requested-With, X-Forwarded-Host, X-Forwarded-Prefix, X-PINGOTHER, Authorization, ES-LongPoll, ES-ExpectedVersion, ES-EventId, ES-EventType, ES-RequiresMaster, ES-HardDelete, ES-ResolveLinkTos
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ES-Position, ES-CurrentVersion
Location: http://127.0.0.1:2113/streams/newstream/2
Content-Type: text/plain; charset=utf-8
Server: Mono-HTTPAPI/1.0
Date: Tue, 14 Aug 2018 10:02:08 GMT
Content-Length: 0
Keep-Alive: timeout=15,max=100
1
2
3
4
5
6
7
8
9
10
11