HTTP Server
omnigraph-server's HTTP surface. Endpoints, auth, error model, admission control.
omnigraph-server is an Axum-based HTTP front end for a single graph
process. Run multiple processes for multi-graph or multi-tenant setups.
For startup options and deployment patterns, see Deployment and Policy for the authorization model.
Endpoint inventory
| Method | Path | Auth action | Purpose |
|---|---|---|---|
GET | /healthz | none | Liveness probe |
GET | /openapi.json | none | OpenAPI schema (strips security scheme when running unauthenticated) |
GET | /snapshot?branch= | read | Snapshot of a branch |
POST | /read | read | Run a named query |
POST | /export | export | Stream the graph as NDJSON |
POST | /change | change | Run a mutation |
GET | /schema | read | Get the current accepted .pg schema |
POST | /schema/apply | schema_apply (target=main) | Apply a migration |
POST | /ingest | branch_create (if new) + change | Bulk load onto a named branch (32 MB body limit) |
GET | /branches | read | List branches |
POST | /branches | branch_create | Create a branch |
DELETE | /branches/{branch} | branch_delete | Delete a branch |
POST | /branches/merge | branch_merge | Three-way merge a source branch into a target |
GET | /commits?branch= | read | List graph commits on a branch |
GET | /commits/{commit_id} | read | Show a single commit |
Only /export streams (application/x-ndjson); every other response is
buffered JSON.
Error model
Every error response uses a uniform shape:
{
"error": "<message>",
"code": "<code>",
"merge_conflicts": [],
"manifest_conflict": null
}code is one of unauthorized, forbidden, bad_request, not_found,
conflict, too_many_requests, internal. merge_conflicts is populated
on branch merge failures; manifest_conflict is set on publisher
compare-and-swap rejections (HTTP 409). It tells the client which (table, branch) raced and what its current manifest version is, so the client can
refresh and retry.
HTTP status codes used: 200, 400, 401, 403, 404, 409, 429, 500.
Per-actor admission control
Disjoint (table, branch) writes from different actors run concurrently. To
prevent one heavy actor from exhausting shared capacity, every mutating
handler is gated through a per-actor workload controller:
| Env var | Default | Purpose |
|---|---|---|
OMNIGRAPH_PER_ACTOR_INFLIGHT_MAX | 16 | Concurrent in-flight mutations per actor |
OMNIGRAPH_PER_ACTOR_BYTES_MAX | 4 GiB | In-flight estimated bytes per actor |
When either ceiling is hit, the server returns HTTP 429 with
code: too_many_requests and a Retry-After header (seconds). Other actors
are unaffected.
Cedar policy authorization runs before admission accounting. Denied requests don't consume admission slots.
Admission gates: /change, /ingest, /branches/{create,delete,merge},
/schema/apply. Read-only endpoints (/snapshot, /read, /export,
/branches GET, /commits, /schema GET) are not admission-gated.
Body limits
- Default request body limit: 1 MB
/ingest: 32 MB
Larger payloads are rejected with 413 Payload Too Large. For bulk loads
beyond 32 MB, drive the load locally with omnigraph load against the
graph URI directly.
Auth model
Bearer tokens are SHA-256 hashed at startup; plaintext never persists in memory. Comparison is constant-time. Tokens map to actor identities, which Cedar policy (if configured) uses for authorization decisions.
Token sources, in priority order:
OMNIGRAPH_SERVER_BEARER_TOKENS_AWS_SECRET. AWS Secrets Manager (requires the--features awsbuild)OMNIGRAPH_SERVER_BEARER_TOKENS_FILEor_JSON. JSON map of{ "<token>": "<actor>" }OMNIGRAPH_SERVER_BEARER_TOKEN. Single legacy token, mapped to actordefault
With no tokens configured, the server refuses to start unless
--unauthenticated (or OMNIGRAPH_UNAUTHENTICATED=1) is set. When that
flag is set, the server runs Open and /openapi.json strips its security
scheme.
The actor identity used for every policy decision comes from the matched bearer token. Clients cannot override it via request header, query parameter, or body field. See Policy for the broader actor-identity contract.
Runtime states
Three startup configurations, classified at boot:
| State | Tokens | Policy file | Behavior |
|---|---|---|---|
| Open | none | none | Every request permitted. Requires explicit --unauthenticated to start. |
| DefaultDeny | yes | none | Every authenticated request for an action other than read returns HTTP 403. Catches the "tokens but no policy" trap. |
| PolicyEnabled | any | yes | Cedar evaluates every request against the configured policy. |
omnigraph policy validate and omnigraph policy explain cover the
PolicyEnabled rules end-to-end without standing up a server. See
Policy.
Tracing and observability
- HTTP requests are traced via
tower_http::TraceLayer::new_for_http(). - Policy decisions log at INFO with actor, action, branch, decision, and matched rule.
- Startup logs include token source name, graph URI, and bind address.
- Graceful SIGINT shutdown.
Not implemented
- CORS. Not configured. Add
tower_http::corsat the edge if a browser client needs it. - Global rate limiting. Per-actor admission handles per-actor backpressure; add
tower_http::limitfor a graph-wide cap. - Pagination. List endpoints return the full set;
/exportstreams. - Multi-tenant routing. One graph per process; run multiple processes for multi-tenancy.