HTTP API (namidb-server)
namidb-server is a single Rust binary (also published as a Docker
image) that opens a namespace and exposes it over HTTP. Same engine as
the embedded library — the only thing this binary adds is the HTTP
boundary, bearer-token auth, and a periodic flush loop.
Install
cargo install --path crates/namidb-serverdocker build -t namidb-server:0.3 \ -f crates/namidb-server/Dockerfile .Run
namidb-server \ --store 's3://my-bucket?ns=prod®ion=us-east-1' \ --listen 0.0.0.0:8080 \ --auth-token "$NAMIDB_AUTH_TOKEN" \ --flush-interval 30sEvery flag is also an env var: NAMIDB_STORE, NAMIDB_LISTEN,
NAMIDB_AUTH_TOKEN, NAMIDB_FLUSH_INTERVAL.
Endpoints (v0)
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /v0/health | public | Liveness + manifest version + epoch |
GET | /v0/version | public | Server build version |
POST | /v0/cypher | bearer | Run a Cypher query (read or write) |
POST | /v0/admin/flush | bearer | Force memtable → L0 SST flush |
POST /v0/cypher
Request
{ "query": "MATCH (p:Person) WHERE p.age >= $min RETURN p.name AS name", "params": {"min": 18}}Response — read
{ "columns": ["name"], "rows": [{"name": "Alice"}, {"name": "Bob"}]}Response — write
{ "columns": ["a"], "rows": [{"a": {"_kind": "node", "id": "…", "label": "Person", "properties": {}}}], "write_outcome": { "nodes_created": 1, "edges_created": 0, "nodes_deleted": 0, "edges_deleted": 0, "properties_set": 0 }}curl round-trip
TOKEN=$(openssl rand -hex 32)
namidb-server --store memory://demo --listen 127.0.0.1:8080 --auth-token "$TOKEN" &
curl -s http://127.0.0.1:8080/v0/health | jq .
curl -s -X POST http://127.0.0.1:8080/v0/cypher \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"query": "CREATE (a:Person {name: \"Alice\", age: 30}) RETURN a.name AS name"}' \ | jq .
curl -s -X POST http://127.0.0.1:8080/v0/cypher \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"query": "MATCH (p:Person) RETURN p.name AS name, p.age AS age"}' \ | jq .Type mapping (JSON ↔ Cypher)
Cypher RuntimeValue | JSON |
|---|---|
Null | null |
Bool | true / false |
Integer | number (i64) |
Float | number (f64) |
String | string |
Bytes | base64 string |
Vector(f32) | array of numbers |
List | array |
Map | object |
Date | ISO-8601 date string |
DateTime (UTC µs) | RFC-3339 timestamp string |
Node | {"_kind": "node", "id", "label", "properties"} |
Rel | {"_kind": "rel", "edge_type", "src", "dst", "properties"} |
Path | array of alternating node/rel objects |
Concurrency model
namidb-server opens one WriterSession per process and serialises
every request behind a tokio Mutex. This is the
single-writer-per-namespace invariant from
RFC-001 lifted up to the
request layer: at most one Cypher statement is in flight against the
namespace at a time. Read latency stays predictable; throughput is
bounded by the slowest mutator.
If you need horizontal read scale today, point multiple
namidb-server processes at the same --store URI: each can serve
reads off the same manifest version. Only one will be allowed to
commit writes (the rest get fenced via epoch CAS).
Concurrent read fan-out without holding the writer mutex is RFC-021 work.
Periodic flush
--flush-interval (default 30s) controls how often the background
task converts the memtable to L0 SSTs. Set it to 0s to disable the
loop and call POST /v0/admin/flush from cron / a sidecar instead.
Roadmap
/v0/cypher/stream— NDJSON streaming response for large result sets./v0/cypher/arrow— Arrow IPC body for zero-copy DataFrame ingestion./v0/metrics— Prometheus exposition.- Bolt protocol compatibility — drivers in every language that already speaks Neo4j today.