# API Gateway A FastAPI-based gateway that exposes a single entrypoint for multiple upstream APIs, with a built-in web management console. ## Features - **Single entrypoint** — consumers call `//` and the gateway proxies to the registered upstream (all HTTP methods, query strings, bodies, headers). `/admin`, `/static`, `/docs` and `/health` are reserved. - **Endpoint catalog, auto-synced** — each service's callable endpoints are mirrored from its OpenAPI document (`/openapi.json`, `/swagger.json` or `/api-docs`) whenever the API Keys page loads: new operations appear, removed ones are deleted (their grants with them). Services without a reachable spec keep their existing catalog. Patterns support `{param}` (one segment), `*` (within a segment) and `**` (any depth). - **Per-key access rights, hierarchical picker** — every API key is granted a specific set of endpoints, chosen in a path tree (service → path segments → operations) where a parent checkbox selects everything beneath it. A request must match a listed endpoint AND the key must hold a grant on it; otherwise 404 (`unknown_endpoint`) or 403 (`access_denied`). Keys are hashed at rest, shown once at creation, revocable, with per-key rate limits. - **Web management console** (`/admin`) — manage connected APIs, users, and API keys; usage dashboards with charts. Every console user has full management access. - **Transaction capture & request browser** — every gateway request is recorded with service, endpoint, key, status, latency, client IP, query string, and the request/response payloads (textual bodies up to 64 KB; binary summarized). The Requests page filters by service / user / key / status class / path and links to a per-request detail view showing the complete transaction. - **Usage monitoring** — charts: traffic and average latency over time (adaptive buckets: 5 min / 1 h / 1 day), volume by service / user / endpoint, status codes, latency by service, top keys — filterable by time range (1 h – 30 d), service, user and key. - **Consumer docs** — `GET /openapi.json` (authenticated with `X-API-Key`) returns a merged OpenAPI document scoped to that key: every operation the key holds a grant on, across all services, rewritten to the gateway's routes. `GET /docs` serves a Swagger UI portal around it — paste a key, browse and try exactly what that key can call. - **Machine catalog** — a hierarchical, key-scoped catalog for agents/MCP clients: `GET /catalog` (available APIs with descriptions), then `/catalog/{slug}` (tags), then `/catalog/{slug}/tags/{tag}` (endpoints; oversized tags group by path prefix, drill with `?prefix=`), then `/catalog/{slug}/operation?method=&path=` (full schema, `$ref`s resolved inline). Authenticated with `X-API-Key`; responses carry ETags. - **Retention** — a background purge runs every 6 hours: request/response payloads are blanked after 7 days (the log row stays inspectable), whole log rows are deleted after 90 days, and freed pages are returned to the filesystem via incremental vacuum. Both windows are configurable; `0` disables that tier. ## Quick start ```bash pip install -r requirements.txt uvicorn app.main:app --host 0.0.0.0 --port 8000 ``` Open http://localhost:8000/admin — first startup seeds an admin account (`admin` / `admin` by default — **change it immediately**). ## Docker ```bash docker compose up -d ``` The console is served on http://localhost:8000/admin; the SQLite database persists in the `gateway-data` volume. Set `GATEWAY_SECRET_KEY` (and the admin credentials) in `docker-compose.yml` before deploying anywhere real. The image runs a single uvicorn worker on purpose — the rate limiter and the OpenAPI sync cache are in-memory. ## Configuration (environment variables) | Variable | Default | Purpose | |---|---|---| | `GATEWAY_DATABASE_URL` | `sqlite:///./gateway.db` | SQLAlchemy database URL | | `GATEWAY_SECRET_KEY` | dev value | Session cookie signing key — set in production | | `GATEWAY_ADMIN_USER` / `GATEWAY_ADMIN_PASSWORD` | `admin` / `admin` | Seeded admin credentials | | `GATEWAY_PAYLOAD_RETENTION_DAYS` | `7` | Blank stored payloads after N days (0 = keep forever) | | `GATEWAY_LOG_RETENTION_DAYS` | `90` | Delete log rows after N days (0 = keep forever) | ## Using the gateway as a consumer 1. Register a service (e.g. slug `weather` → `https://api.example.com/v1`) and list its endpoints (import from OpenAPI or add manually). 2. Issue an API key and tick the endpoints it may call. 3. The consumer calls: ```bash curl -H "X-API-Key: gw_..." "http://localhost:8000/weather/forecast?city=Paris" ``` The gateway authenticates the key, matches the request against the service's endpoint list, checks the key's grant and the rate limit, proxies the request to `https://api.example.com/v1/forecast?city=Paris`, logs it, and returns the upstream response. Gateway-generated errors are JSON with an `error` code: `missing_api_key` (401), `invalid_api_key` / `access_denied` (403), `unknown_service` / `unknown_endpoint` (404), `rate_limited` (429), `upstream_unreachable` (502), `upstream_timeout` (504). ## Notes & limits - The stats queries use SQLite date functions; if you point `GATEWAY_DATABASE_URL` at Postgres/MySQL, adapt `app/admin/stats.py` (`strftime`, `iif`). - The rate limiter is in-memory (single process). Run one worker, or swap in Redis for multi-worker deployments. - Streaming responses are buffered (fine for JSON APIs; not for large file proxying).