HTTP API
HTTP/1.1 and JSON on a unix socket, and on TCP when listen.tcp is set. With -token-file, every TCP request needs Authorization: Bearer <token> (else 401 unauthorized); the unix socket needs none. Debug with curl --unix-socket /run/ndb/ndb.sock http://ndb/health. The host name in the URL does not matter on a unix socket.
Paths start with /v1. /health and /metrics have no version. Every data endpoint answers 503 not_ready until recovery ends.
| Method | Path | Body | Answer |
|---|---|---|---|
| POST | /v1/c/{coll}/find | find query | NDJSON rows + X-Ndb-* headers |
| POST | /v1/c/{coll}/aggregate | {"pipeline":[...]} | NDJSON rows + X-Ndb-* headers |
| POST | /v1/c/{coll}/insert | {"insert":[{...},...]} | {"results":[{"id","v"}]} |
| POST | /v1/c/{coll}/update | {"update":{"id","set","unset","if_version"}} | {"id","v"} |
| POST | /v1/c/{coll}/delete | {"delete":{"id","if_version"}} | {"id"} |
| POST | /v1/c/{coll}/watch | {"consumer","from","limit","where"} | NDJSON stream |
| POST | /v1/c/{coll}/ack | {"consumer","pos"} | {"ok":true} |
| PUT | /v1/c/{coll} | collection definition | {"definition","indexes"} |
| GET | /v1/c | none | {"collections":[...]} |
| DELETE | /v1/c/{coll}/indexes/{field} | none | {"collection","indexes"} |
| GET | /v1/c/{coll}/stats | none | rows, quarantined, index state |
| PUT | /v1/blobs | raw bytes | the $blob reference |
| GET | /v1/blobs/{ref} | none | the bytes; supports Range |
| POST | /v1/backup | {"dest":"/path"} | unix socket only |
| GET | /health | none | {"status":"ok"}, or 503 recovering |
| GET | /metrics | none | Prometheus text |
Details:
- Request bodies are limited by the collection
max_line_size(default 1 MiB). Unknown JSON fields areinvalid_request. insertcreates an unknown collection (unlessallow_implicit: false). A document without the id field gets a generated id. Insert on a direct-mode collection isdirect_collection.updatemergesset(dot paths allowed) and removes the paths inunset. The id cannot change (immutable_id).if_versionmakes the write conditional: a different current version isversion_conflict.PUT /v1/c/{coll}is idempotent. Keys:id,time,write,path,indexes,unique,durability,retention,wal_retention,ttl,expires_field,max_line_size,blob_threshold(bytes). Merge rules:indexesare united; a differentid,write,pathortimeiscatalog_conflict;ndb.ymlwins fordurability,retentionandwal_retention.statsshowsrows,quarantinedand each index asbuildingorready, withdoneandtotal.- Errors are described in query.md.
whereoperators are in query.md.{"field": {"$regex": "^abc", "$options": "i"}}matches strings with Go RE2 (no backreferences, no look-around; flagsi,m,s,x); a bad pattern or flag is400 invalid_query. An anchored literal prefix withouti/mcan use an index and zone maps, see Regular expressions.
watch and ack
watch is a long-lived stream, one JSON object per line. from is beginning or now and is used only for a consumer with no saved position. A consumer that acked before resumes after its last ack.
{"pos":"e1.1","op":"put","id":"c1","v":1,"doc":{"_id":"c1","status":"answered"}}
{"pos":"e1.2","op":"del","id":"c2","v":2}
{"heartbeat":true}
{"error":{"code":"watch_lagged","message":"..."}}opisputordel. A delete by the TTL sweeper has"_expired": true.- A heartbeat line comes after 15 s without events.
wherehas the same operators asfind. Aputis sent when its document matches. Adelhas no document, so it is sent only if the lastputof that id seen by this stream matched (the stream remembers the last 65 536 ids). Events that are left out still move the saved position.limitcloses the stream after that many events (0 = no limit).ackstores theposof an event the consumer has processed. Delivery is at least once.watch_laggedmeans the consumer was too slow. Reconnect: the stream resumes from the last ack.history_truncated(HTTP 410) means the WAL files that the watch must read were deleted bywal_retention(no saved position withfrom: "beginning", or a position before the oldest kept file). The stream never skips the gap in silence. Start fromnow, or rebuild fromfind. A saved position is safe: ndb keeps the file that holds it.
Backup endpoint
POST /v1/backup writes to the disk of the daemon host, so it works on the unix socket only. Over TCP the answer is 403 forbidden. Use ndb backup instead of calling it by hand. See operations.md.
Blobs
PUT /v1/blobs with the raw body returns the reference to keep in a document: {"$blob":"sha256:<hex>","size":N,"type":"..."}. GET /v1/blobs/sha256:<hex> streams the content (?type= sets the content type). The limit is blob_max_size (default 1 GiB).