Aggregates
An aggregate is the current state derived from replaying all events for a given type and ID.
How aggregates work
When you query an aggregate, j17 replays all events and applies each handler in order:
Event 1: was_created { name: "Alice" } -> State: { name: "Alice", created_at: 1705312800 }
Event 2: had_email_updated { email: "..." } -> State: { name: "Alice", email: "...", created_at: ... }
Event 3: had_name_updated { name: "Alicia" } -> State: { name: "Alicia", email: "...", created_at: ... }
Each event type has a handler defined in your spec that determines how it transforms state. For example:
{
"was_created": {
"handler": [
{ "set": { "target": "", "value": "$.data" } },
{ "set": { "target": "created_at", "value": "$.metadata.timestamp" } }
]
},
"had_name_updated": {
"handler": [
{ "merge": { "target": "", "value": "$.data" } }
]
}
}
Querying aggregates
curl https://myapp.j17.dev/user/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $J17_API_KEY"
Response:
{
"ok": true,
"state": {
"name": "Alicia",
"email": "alice@example.com",
"created_at": 1705312800
},
"length": 3
}
The length field indicates how many events have been applied. You can use this for optimistic concurrency control.
Aggregate IDs
Aggregate IDs in URLs accept three formats:
| Format | Example | Use case |
|---|---|---|
| UUIDv4 | 550e8400-e29b-41d4-a716-446655440000 |
Default for all entities |
| Humane code | ABC123XYZ |
Human-readable codes (promos, bookings) |
global |
global |
Singleton aggregates (config, rate limits) |
Use UUIDs by default. Humane codes and singletons exist for specific edge cases.
Can't find what you need? support@j17.app