Files
Api-Gateway/README.md
T
Samuel AmarandClaude Fable 5 d5878f6130 Add per-key OpenAPI document and Swagger UI portal
GET /openapi.json (X-API-Key authenticated) merges the upstream OpenAPI
documents into one spec scoped to the calling key: only granted
operations, paths rewritten to gateway routes, component schemas
namespaced per service. GET /docs serves a Swagger UI portal that loads
the key-scoped spec and injects the key into try-it-out requests.

Discovery now caches the raw upstream spec documents (same 5-minute
TTL), and FastAPI's built-in /docs and /openapi.json are disabled in
favor of the portal routes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 14:27:44 +02:00

105 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 `/<service-slug>/<path>` 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.
- **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).