The most popular client for EventStoreDB is the dotnet client, so naturally, this makes the library easy to use in F# as well. The first part is creating a project.

Disclaimer #1: I am still new to FSharp/F# so it is likely that the code is not as elegant as you would expect.

Disclaimer 2: This uses F# 6

dotnet new console -lang "F#" -o project_folder_name

Next we need to import the following libraries

https://www.nuget.org/packages/EventStore.Client.Grpc

https://www.nuget.org/packages/EventStore.Client.Grpc.Streams

dotnet add package EventStore.Client.Grpc --version 22.0.0
dotnet add package EventStore.Client.Grpc --version 22.0.0

You should be ready to use the library. Let’s get started with connecting to an EventStoreDB instance.

Import the library with:

open EventStore.Client

Then connect to the instance by providing a connection string.

let client = EventStoreClientSettings.Create "esdb://127.0.0.1:2113?tls=false"
             |> EventStoreClient

The code above initialises an EventStoreDB client with a connection string telling the telling to connect to a single EventStoreDB instance running in insecure mode on localhost listening on the default HTTP port 2113.

After that you have to create a list of events to write. You can do that as follows:

let streamName = "sample_stream"
let eventData = EventData(
                    Uuid.NewUuid(),
                    "event_type",
                    ReadOnlyMemory<byte>(Encoding.UTF8.GetBytes("{\"some\":\"json data here\"}"))
                )
let eventsList  = List<EventData>()
eventsList.Add(eventData)

Feel free to wrap this in style with a record and functions to make it sexy. Basically we are create one event and adding it to a System.Collections.Generic List. You will likely need to import this.

After that writing events can be done as follows:

try
    let result = client.ConditionalAppendToStreamAsync(streamName, StreamState.Any, eventsList).Result
    match result.Status with
    | ConditionalWriteStatus.Succeeded -> printfn "Events were written!"
    | ConditionalWriteStatus.StreamDeleted -> printfn $"Didn't expect stream to be deleted"
    | ConditionalWriteStatus.VersionMismatch -> printfn $"You should read https://developers.eventstore.com/clients/dotnet/21.2/appending.html#idempotence"
    | _ -> printfn $"unknown outcome! {result.Status}"
with
    | _ as e -> printfn$"{e.Message}"

We are trying to write with ConditionalAppendToStreamAsync, synchronously waiting for the result and matching the status with different outcomes. At the moment we have the versioning to Any, you might want to read about what that means and idempotency in EventStoreDB: https://developers.eventstore.com/clients/dotnet/21.2/appending.html#idempotence

Reading the event written is a bit trickier, you have to use TaskSeq to handle the IAsyncEnumerable returned. So you will first need to import https://github.com/fsprojects/FSharp.Control.TaskSeq

dotnet add package FSharp.Control.TaskSeq --version 0.3.0

You can then do a read backwards, of 1 event (1L means one Long) starting from the end of the stream.

client.ReadStreamAsync(Direction.Backwards,
                       streamName,
                       StreamPosition.End,
                       1L, 
                       true)
    |> TaskSeq.iter (fun event -> printfn$"
                      data: {Encoding.UTF8.GetString(event.OriginalEvent.Data.ToArray())}")
    |> ignore
//probably need to wait here

I hope this has helped you get started with FSharp/F# and EventStoreDB. In this short post we have seen how to write and read events. There are more exciting things that you can do with EventStoreDB, so let me know if you would like to see more posts like this!