CRUMB a card from devarno-cloud

Engine REST API Surface

nestr intermediate 5 min read

ELI5

The engine’s front door has a lobby (/health, /ready, /metrics, /ws handshake) and a set of rooms under /api. Rooms need a key card when the engine was started with a key reader, every room has a turnstile, and two kinds of room also count how often a free-plan organisation has used them this month.

Technical Deep Dive

Source: nestr-tools/engine internal/server/rest.go:94-170,172-200,248,282-292,486-527,529-545,600-602, internal/server/pellet_handlers.go:44-47, internal/server/usage.go:80-130, go.mod @e9180e4, read 2026-10-25. The previous revision said the router was stdlib http.ServeMux with handler-level 405s; it is gorilla/mux with .Methods(...).

Middleware order

flowchart LR
REQ["request"] --> LOG["loggingMiddleware: X-Request-ID, timing"]
LOG --> CORS["corsMiddleware: CORS_ALLOWED_ORIGINS"]
CORS --> MUX["gorilla/mux route match"]
MUX --> AUTH["auth.Middleware on /api, only if JWKS_URL set"]
AUTH --> RL["withRateLimit: 10 rps, burst 20 per IP"]
RL --> Q["withQuota on capped routes"]
Q --> H["handler"]

Routes

MethodPathAuthExtra
GET/health, /readynoneno rate limit
GET/metricsnonePrometheus, unguarded (nestr-008)
GET/wsJWT via query or header when auth is onevent fan-out (nestr-007)
GET/api/workspace, /api/servicesJWTrate limit
POST/api/operations/run, /sync, /assembleJWTrate limit, Community cap
GET/api/usageJWTsecurity record, never capped
GET/api/pellets, /api/pellets/{id}, /api/pellets/statsJWTrate limit
POST/api/pellets/compressJWTrate limit, Community cap
POST/api/pellets/extractJWTrate limit; verification gate, never capped
POST/api/pellets/pruneJWTrate limit
OPTIONSanynone204 preflight
flowchart TD
API["/api subrouter"] --> J{"JWKS_URL set at start?"}
J -- "no" --> OPEN["routes open, WARN logged"]
J -- "yes" --> CHK["EdDSA JWT, iss and aud enforced"]
CHK --> CAP{"compress or operations?"}
CAP -- "yes" --> QUOTA["withQuota"]
CAP -- "no" --> HAND["handler"]
QUOTA --> HAND

Responses

Success is the resource as JSON, or {success, message, ...} on write routes. Errors use one envelope: {"error": {"code": <http status>, "message": ..., "type": ...}, "request_id": ...} (rest.go:486-515), where request_id is the X-Request-ID the logging middleware set (inbound header, else <unixnano>-<remote addr>). Quota refusals use their own body with a string code such as E_FREE_QUOTA_EXCEEDED (nestr-025).

Key Terms

  • gorilla/mux → the engine’s HTTP router; method matching via .Methods.
  • withQuota → Community monthly cap middleware on compress and operations.
  • CORS_ALLOWED_ORIGINS → CSV; default http://localhost:3000,http://localhost:5173,https://app.nestr.tools.

Q&A

Q: Which router does the engine use, and what middleware wraps every route? A: gorilla/mux. Every route passes loggingMiddleware then corsMiddleware; /api routes add the JWT middleware when enabled, the per-IP rate limiter, and on capped routes withQuota.

Q: Which routes have no auth even when JWKS_URL is set? A: /health, /ready, /metrics and the OPTIONS preflight. /ws checks the token itself during the handshake.

Q: What does an engine error body look like? A: {"error":{"code":<status>,"message":"...","type":"..."},"request_id":"..."}, with type derived from the status: client_error for 4xx, server_error for 5xx (rest.go:518-527).

Examples

curl -X POST https://<engine>/api/pellets/extract -H "Authorization: Bearer $JWT" -d '{"pelletId":"pid:blake3:..."}' runs the verification gate; whatever the plan, it is never refused for quota, and the outcome is recorded in the organisation’s security record. The engine’s public hostname was not confirmed for this card (UNVERIFIED).

neighbors on the map