Quick Start
In this guide, you’ll:
- Start an EvidentSource server locally
- Create a database and store your first events
- Query events using the TypeScript client or REST API
- Execute a State Change and query a State View
New to event sourcing? Read What is EvidentSource? first to understand the programming model and benefits.
This guide will help you get EvidentSource up and running quickly using the in-memory adapter for local development.
Prerequisites
Section titled “Prerequisites”- Docker and Docker Compose (see Installation Guide)
- Node.js 20+ and pnpm (for TypeScript examples)
Start the Server
Section titled “Start the Server”Using Docker Compose (Recommended)
Section titled “Using Docker Compose (Recommended)”Clone the SDK repository and start the development server:
# Clone the repositorygit clone https://github.com/evidentsystems/evidentsource-sdkscd evidentsource-sdks
# Start the server with docker composedocker compose -f docker-compose.evidentsource.yml up -dThe server will start with:
- HTTP API at
http://localhost:3000 - gRPC API at
localhost:50051 - Web UI at
http://localhost:3000
Verify the Server is Running
Section titled “Verify the Server is Running”curl http://localhost:3000/health# Returns: OKCreate Your First Database
Section titled “Create Your First Database”Using the REST API
Section titled “Using the REST API”curl -X POST http://localhost:3000/api/v1/databases/mydbUsing the TypeScript Client
Section titled “Using the TypeScript Client”First, set up a project:
mkdir quickstart && cd quickstartpnpm initpnpm add github:evidentsystems/evidentsource-sdks#main:typescript/packages/evidentsource-corepnpm add github:evidentsystems/evidentsource-sdks#main:typescript/packages/evidentsource-clientCreate index.ts:
import { EvidentSource, databaseName, DatabaseError,} from "@evidentsource/client";
async function main() { // Connect to the server const es = EvidentSource.connect("http://localhost:50051");
// Create a database const dbName = databaseName("mydb"); try { await es.createDatabase(dbName); console.log("Database created!"); } catch (e) { if (e instanceof DatabaseError && e.code === "ALREADY_EXISTS") { console.log("Database already exists"); } else { throw e; } }
es.close();}
main().catch(console.error);Write Your First Events
Section titled “Write Your First Events”Events are stored via transactions with optimistic concurrency control:
import { EvidentSource, databaseName, streamName, eventType, subject, prospectiveEvent,} from "@evidentsource/client";import { v4 as uuidv4 } from "uuid";
async function main() { const es = EvidentSource.connect("http://localhost:50051"); const dbName = databaseName("mydb"); const conn = await es.connectDatabase(dbName);
// Create events const events = [ prospectiveEvent({ id: uuidv4(), stream: streamName("users"), type: eventType("com.example.user.created"), subject: subject("user-123"), data: JSON.stringify({ username: "alice", email: "alice@example.com", }), dataContentType: "application/json", }), ];
// Commit the transaction const db = await conn.transact(events); console.log(`Events stored at revision: ${db.revision}`);
await conn.close(); es.close();}
main().catch(console.error);Query Events
Section titled “Query Events”Query by Stream
Section titled “Query by Stream”Get all events from a specific stream:
import { EventSelector, streamName } from "@evidentsource/core";
// Query events from the "users" streamconst events = await db.queryEvents({ selector: EventSelector.streamEquals(streamName("users")), limit: 100,});
for (const event of events) { console.log(`${event.type}: ${event.data}`);}Query by Subject
Section titled “Query by Subject”Get all events for a specific entity:
import { EventSelector, subject } from "@evidentsource/core";
// Query all events for user-123const userEvents = await db.queryEvents({ selector: EventSelector.subjectEquals(subject("user-123")),});Execute a State Change
Section titled “Execute a State Change”State Changes are WebAssembly components that handle commands and emit events. Once deployed to the server:
import { stateChangeName, jsonCommandRequest,} from "@evidentsource/client";
// Execute a state changeconst db = await conn.executeStateChange( stateChangeName("create-user"), 1, // version jsonCommandRequest({ userId: "user-456", username: "bob", email: "bob@example.com", }));
console.log(`State change executed, new revision: ${db.revision}`);Query a State View
Section titled “Query a State View”State Views are WebAssembly components that materialize read models from events:
import { stateViewName, stateViewContentAsJson, stringAttribute,} from "@evidentsource/client";
// Query a state viewconst params = new Map([["user_id", stringAttribute("user-123")]]);const view = await db.viewStateWithParams( stateViewName("user-profile"), 1, // version params);
if (view) { interface UserProfile { id: string; username: string; email: string; } const profile = stateViewContentAsJson<UserProfile>(view); console.log(`User: ${profile.username} (${profile.email})`);}Using the REST API
Section titled “Using the REST API”All operations are also available via REST:
# Create a databasecurl -X POST http://localhost:3000/api/v1/databases/mydb
# Execute a state changecurl -X POST http://localhost:3000/api/v1/databases/mydb/state-changes/create-user/versions/1 \ -H "Content-Type: application/json" \ -d '{"userId": "user-789", "username": "carol", "email": "carol@example.com"}'
# Query a state viewcurl "http://localhost:3000/api/v1/databases/mydb/state-views/user-profile/versions/1?user_id=user-123"Next Steps
Section titled “Next Steps”Build State Changes and State Views
Section titled “Build State Changes and State Views”State Changes and State Views are WebAssembly components built with our SDKs:
- Rust SDK - Reference implementation
- Go SDK - TinyGo-based WASM
- Python SDK - Componentize-py WASM
- .NET SDK - WASI workload (Windows only)
- TypeScript SDK - Client applications
Explore Example Applications
Section titled “Explore Example Applications”Complete examples are available in the SDK repository:
- TodoMVC - Classic task management
- Savings Account - Banking with bi-temporal queries
Deploy to Production
Section titled “Deploy to Production”For production deployment, see our AWS Deployment Guide.
Learn More
Section titled “Learn More”- Core Concepts - Understand event sourcing fundamentals
- State Changes - Command handling with WASM
- State Views - Materialized read models
- API Reference - Complete API documentation
Troubleshooting
Section titled “Troubleshooting”Port Already in Use
Section titled “Port Already in Use”If port 3000 is taken, modify the docker-compose environment:
environment: EVIDENT_HTTP_PORT: "3001"ports: - "3001:3001"Connection Refused
Section titled “Connection Refused”Ensure the server is running:
# Check server healthcurl http://localhost:3000/health
# Check container statusdocker compose -f docker-compose.evidentsource.yml psView Server Logs
Section titled “View Server Logs”docker compose -f docker-compose.evidentsource.yml logs -f evidentsourceGetting Help
Section titled “Getting Help”- Documentation: You’re reading it!
- GitHub Issues: github.com/evidentsystems/evidentsource-sdks
- Support: support@evidentsource.com