Four interfaces, one cache
Aeron Cache exposes the same key-value and counter model over four interfaces. They share one command vocabulary — create, put, get, patch, remove, TTL, counters, bulk ops, and streaming subscriptions — and differ only in framing, directionality, and how far down the latency curve they reach. Pick by the shape of your client, not by habit.
- Start with HTTP for CRUD, scripting, tooling, and anything that just needs request/response. It is always on.
- Add WebSocket or SSE when you need to receive updates as they happen rather than poll.
- Use the bidirectional WebSocket when one client needs both the full command surface and dynamic subscriptions over a single socket.
- Reach for the Aeron SBE gateway when you are latency-sensitive and can run a Java or Rust client — binary, zero-copy, bidirectional over Aeron UDP or IPC.
Every response carries an operationStatus (a business status such as SUCCESS, UNKNOWN_CACHE, UNKNOWN_KEY, or CACHE_EXISTS) rather than relying on HTTP codes alone, so clients inspect the status instead of catching exceptions on a 400.
When to use which interface
| Interface | Port / base path | Directionality | Streaming | Format | Enable flag (default) | Spec file |
|---|---|---|---|---|---|---|
| HTTP REST | :7070 /api/v1 | Request → response | No | JSON | Always on | cache-http/openapi.yml |
| WebSocket (uni) | :7071 /api/ws/v1/... | Server → client (on a subscribe route) | Yes (receive) | JSON | WEBSOCKET_GATEWAY_ENABLED (true) | cache-ws/ws-openapi.yaml |
| WebSocket (bidi) | :7071 /api/ws/v1/bidi | Bidirectional | Yes | JSON | WEBSOCKET_GATEWAY_ENABLED (true) | cache-ws/bidi-ws-openapi.yaml |
| SSE | :7072 /api/sse/v1/... | Server → client only | Yes (receive) | text/event-stream | SSE_GATEWAY_ENABLED (true) | cache-sse/sse-openapi.yaml |
| Aeron SBE gateway | UDP :7075 / :7076 or IPC | Bidirectional | Yes | SBE binary (schema id 7) | AERON_GATEWAY_ENABLED (false) | gateway-schema.xml |
Counter-specific routes mirror the above and have their own specs: cache-http/counters-openapi.yml, cache-ws/counters-ws-openapi.yaml, and cache-sse/counters-sse-openapi.yaml. The near-cache has cache-near/openapi.yml. The Aeron gateway’s transport media is selected with GATEWAY_TRANSPORT_MEDIA (udp or ipc).
Decision shortcut: CRUD or tooling → HTTP. Receive-only updates in a browser → SSE. Receive-only updates in a service → uni WebSocket. Commands and subscriptions over one socket → bidi WebSocket. Lowest latency on the JVM or in Rust → Aeron SBE gateway.
HTTP REST in practice
The HTTP API is served by Javalin under the base path /api/v1. The examples below run against the default local server (http://localhost:7070) and are verified against cache-http/openapi.yml. Values are strings; to store JSON, pass the JSON document as the value string (which is also what makes it patchable).
Create a cache
# POST /api/v1/cache — body names the cache to create.
curl -X POST http://localhost:7070/api/v1/cache \
-H 'Content-Type: application/json' \
-d '{"cacheId": "quotes"}'
# -> {"cacheId":"quotes","operationStatus":"SUCCESS"}
Put an item
# POST /api/v1/cache/{cacheId} — key + value go in the body.
curl -X POST http://localhost:7070/api/v1/cache/quotes \
-H 'Content-Type: application/json' \
-d '{"key": "EURUSD", "value": "{\"bid\":1.0871,\"ask\":1.0873}"}'
# -> {"cacheId":"quotes","key":"EURUSD","operationStatus":"SUCCESS"}
To store an item with a TTL, POST to /api/v1/cache/timed/{cacheId} with an added ttl (milliseconds):
# POST /api/v1/cache/timed/{cacheId} — value expires after ttl ms.
curl -X POST http://localhost:7070/api/v1/cache/timed/quotes \
-H 'Content-Type: application/json' \
-d '{"key": "EURUSD", "value": "{\"bid\":1.0871}", "ttl": 60000}'
Get an item
# GET /api/v1/cache/{cacheId}/{key}
curl http://localhost:7070/api/v1/cache/quotes/EURUSD
# -> {"cacheId":"quotes","key":"EURUSD","value":"{\"bid\":1.0871,\"ask\":1.0873}","operationStatus":"SUCCESS"}
Patch an item (JSON Merge Patch, RFC 7386)
# PATCH /api/v1/cache/{cacheId}/{key} — deep-merge the supplied fields into the stored JSON.
curl -X PATCH http://localhost:7070/api/v1/cache/quotes/EURUSD \
-H 'Content-Type: application/json' \
-d '{"value": "{\"bid\":1.0875}"}'
# -> {"cacheId":"quotes","key":"EURUSD","operationStatus":"SUCCESS"}
# Only "bid" changes; "ask" is untouched. A null field value deletes that field.
Other HTTP routes follow the same shape: GET /api/v1/cache/{cacheId} (all items), PATCH /api/v1/cache/{cacheId} (clear), DELETE /api/v1/cache/{cacheId} (delete cache), DELETE /api/v1/cache/{cacheId}/{key} (remove item), POST /api/v1/cache/{cacheId}/{key}/cancel-removal (cancel a scheduled TTL removal), POST /api/v1/cache/bulkops (atomic batch, mixing cache and counter ops), and the inspection routes GET /api/v1/caches, GET /api/v1/stats, and GET /api/v1/timers. Cluster operators also have POST /api/v1/snapshot, POST /api/v1/snapshot-and-purge, and GET /api/v1/snapshot-info.
Streaming interfaces in brief
The uni-directional WebSocket and SSE routes are subscribe-by-URL: you connect to a cache (or comma-separated caches), optionally filter with a keys query parameter and choose mode=full (default) or mode=patch, and receive CacheUpdateEvent frames with an eventType of ADD_ITEM, PATCH_ITEM, REMOVE_ITEM, CLEAR_CACHE, or DELETE_CACHE. Hydrating variants (.../hydrate/...) replay current state first.
# SSE: stream patch-mode deltas for two caches, filtered to specific keys.
curl -N "http://localhost:7072/api/sse/v1/caches/quotes,rates?mode=patch&keys=quotes:EURUSD"
The bidirectional WebSocket (/api/ws/v1/bidi) carries the full surface over one JSON connection: command, subscribe, unsubscribe, and bulk frames in, commandResponse, streamUpdate, entries, stats, bulkResponse, subscribed, and error frames out — each correlated by a client-generated correlationId. The subscribed ack acts as a barrier, so you can wait for a subscription to be live before issuing mutations you expect to be streamed back. The Aeron SBE gateway offers the same bidirectional model as a binary, zero-copy protocol; its internals are covered in Aeron + SBE transport.
Where to go next
- Raw specs live in the repo at github.com/bhf/aeron-cache:
cache-http/openapi.yml,cache-ws/ws-openapi.yaml,cache-ws/bidi-ws-openapi.yaml,cache-sse/sse-openapi.yaml, and the SBE schema undercache-aeron-gateway/. - Pick a client at embedded clients — Java, TypeScript, Python, and Rust embedded clients (plus the Rust CLI) wrap all of the above, including the embedded-mirror and patch-mode subscription patterns.
- Get it running at Getting Started, then see how Aeron Cache compares and the use-case patterns.