Set up the TodoMVC example
The TodoMVC example is a small, complete EvidentSource application: five State Changes that create, rename, complete, delete and clear todos, and two State Views that read them back. This page builds it, publishes it to a database of your own, and runs it.
It takes a few minutes, most of them spent compiling.
What you need
Section titled “What you need”- Rust, with the WebAssembly target:
rustup target add wasm32-wasip2 - git and curl
- A server: the public Sandbox, or one on your machine.
1. Choose a server
Section titled “1. Choose a server”The Sandbox. Nothing to install. It is shared and public, and its data is purged periodically; read About the Sandbox first.
export EVIDENTSOURCE_URL=https://sandbox.evidentsource.comYour machine. Run the development image with in-memory storage. Data is lost when the container stops.
docker run -d -p 3000:3000 -p 50051:50051 evidentsource/evidentsource-dev:0.8.38@sha256:16c279e5dee4a1b0e3951067ed871040251266fd1d7404554744b31b04bbbc69 \ server --scheme http --dev --node-id node-1 --writer memory
export EVIDENTSOURCE_URL=http://localhost:3000--writer matters: a lone server started without it refuses every write.
2. Create a database
Section titled “2. Create a database”Database names must be unique on a server. The Sandbox is shared, so include something of your own in the name:
export EVIDENTSOURCE_DATABASE=todomvc-yourname
curl -X POST "$EVIDENTSOURCE_URL/api/v1/db" \ -H 'Content-Type: application/json' \ -d "{\"database_name\": \"$EVIDENTSOURCE_DATABASE\"}"A new database answers 200 on the pinned local release above and 201 on the current server. A name that is taken answers 409: pick another.
3. Build the components
Section titled “3. Build the components”git clone https://github.com/evidentsystems/evidentsource-sdks.gitcd evidentsource-sdks/rust/examples/todomvc./build_all.shThis compiles each State Change and State View to a WebAssembly component under target/wasm32-wasip2/release/.
4. Publish them
Section titled “4. Publish them”install.sh publishes to $EVIDENTSOURCE_URL and $EVIDENTSOURCE_DATABASE:
./install.sh --allAnswer y to the prompt. Each component uploads with its metadata.json, which names it and, for a State View, says which events it reads. The first publish of each is version 1.
Uploading state change create-todo... ok … Uploading state view todo-list... ok5. Create a todo
Section titled “5. Create a todo”A todo’s id is a UUID you choose.
export TODO_ID=3f0b5a0e-1c2d-4e5f-8a9b-0c1d2e3f4a5b
curl -X POST "$EVIDENTSOURCE_URL/api/v1/db/$EVIDENTSOURCE_DATABASE/latest/state-changes/create-todo/v1" \ -H 'Content-Type: application/json' \ -d "{\"todoId\": \"$TODO_ID\", \"title\": \"Try EvidentSource\", \"effectiveTimestamp\": \"2026-09-17T00:00:00Z\"}"The reply is the transaction the command committed, with the revision it reached:
{"id":"01a0ad3f-…","database":"todomvc-yourname","revision":"1","timestamp":"…","metadata":{"origin":{"httpStateChange":{"name":"create-todo","version":"1"}}}}6. Read it back
Section titled “6. Read it back”curl -L "$EVIDENTSOURCE_URL/api/v1/db/$EVIDENTSOURCE_DATABASE/latest/state-views/todo-list/v1"{"todos":[{"id":"3f0b5a0e-1c2d-4e5f-8a9b-0c1d2e3f4a5b","title":"Try EvidentSource","completed":false,"createdAt":"2026-09-17T00:00:00Z"}]}latest redirects to the database’s current revision, so pass -L.
single-todo reads one todo. Its events are selected by subject, bound with a query parameter:
curl -L "$EVIDENTSOURCE_URL/api/v1/db/$EVIDENTSOURCE_DATABASE/latest/state-views/single-todo/v1?subject.todo_id=$TODO_ID"7. Complete it
Section titled “7. Complete it”curl -X POST "$EVIDENTSOURCE_URL/api/v1/db/$EVIDENTSOURCE_DATABASE/latest/state-changes/toggle-todo/v1" \ -H 'Content-Type: application/json' \ -d "{\"todoId\": \"$TODO_ID\", \"effectiveTimestamp\": \"2026-09-17T00:05:00Z\"}"Read single-todo again, and it shows "completed": true, with completedAt taken from the command’s effectiveTimestamp.
The components
Section titled “The components”| State Change | Body |
|---|---|
create-todo | todoId, title, effectiveTimestamp |
rename-todo | todoId, title, effectiveTimestamp |
toggle-todo | todoId, effectiveTimestamp |
delete-todo | todoId, effectiveTimestamp |
clear-completed | effectiveTimestamp |
| State View | Reads | Parameters |
|---|---|---|
todo-list | every event in the todos stream | none |
single-todo | the events whose subject is one todo | subject.todo_id |
Every event is in the todos stream, with the todo’s id as its subject.
When something fails
Section titled “When something fails”400withvalidation error: the command was refused. The message says why: an empty title, or a missing field such aseffectiveTimestamp.404on a command or view: check the database name, and thatinstall.shpublished that component.install.shsays a.wasmfile is missing: run./build_all.shfirst.
- Issuing commands and Reading state views explain the two routes you just used.
- State Changes & State Views explains what the components do.
- Each language in the SDK repository has the same TodoMVC example, under
<language>/examples/todomvc/(dotnet/examples/TodoMvc/for .NET). This page follows the Rust one.