- Extract `apikey:` header (case-insensitive header name, exact value match against stored key)
- If missing or unrecognized → 401 with `{"error":"unauthorized","reason":"missing apikey header"}`
- Pass apikey to request context so handlers can log which key made the request
7. CORS: disable (agents are internal cluster; no browser requests expected)
8. Health check: `GET /health` returns 200 `{"status":"ok","uptime_seconds":N}`
## Acceptance
- Server starts without errors
- Health check responds
- Three routes defined and callable
- Auth middleware rejects missing apikey (401)
- Request logger emits latency per request
- Metrics collected (observable via endpoint or in-process)
## Verify
**Harness:** Integration tests against a live server instance started in each test.
**Integration test** — `tests/it_http_server.rs`:
1.`a1_server_starts` — `HttpServer::new(...).run()` succeeds, port is open.
2.`a2_health_check` — GET /health returns 200 and body contains `"ok"`.
3.`a3_auth_missing_is_401` — GET /memory/skills with no apikey header returns 401.
4.`a4_auth_wrong_is_401` — GET /memory/skills with `apikey: wrong` returns 401.
5.`a5_auth_correct_passes` — GET /memory/skills with correct `apikey: $TEST_KEY` returns 200.
6.`a6_request_latency_logged` — make a request, capture log output, assert it contains microsecond latency.
7.`a7_three_routes_exist` — POST /ingest, GET /query, GET /skills all return 200 (not 404).
8.`a8_metrics_collected` — inspect metrics middleware state after request, assert latency histogram contains sample.
**Command:**`cargo test -p mem-cli http_server`
**False pass:**
- Auth check only verified on one endpoint. Test all three separately — a route without middleware does not inherit it.
- Metrics collected but never asserted. A metrics middleware that silently fails still compiles.
- Latency logged in milliseconds. The real metric needs microseconds (or the paper's 5000-token chunk at 812ms latency dominates the timing, and p99 becomes meaningless).
## Traps
- Actix-web's `.service()` does not inherit middleware registered outside a scope; scope middleware applies only to routes inside that scope.
-`tokio::runtime::Runtime::new()` in tests blocks on network if used naively — use test utilities from `actix-web` or `axum` that spawn the server in a background thread.
- Metrics registered at startup are easy to forget to increment. Middleware must actually call the metrics update, not just define it.
---
Background: [DESIGN.md § Distributed API Layer](../DESIGN.md#distributed-api-layer-homelab-frontend)