API gateway service built with FastAPI and Poetry. It provides CORS, versioned routes, JWT validation via an external auth service, rate limiting, and a YAML-backed proxy router with regex matching and rewrites.
- Versioned API prefix (
/api/v1). - CORS configurable via environment variables.
- JWT validation + authorization delegated to
auth_service. - Rate limiting with
X-RateLimit-*headers. - Dynamic proxy routes stored in
routes.yaml. - Admin CRUD endpoints to manage routes.
- Python 3.11+
- Poetry
poetry install
cp env.example .env
poetry run fastapi runThe fastapi command is wrapped to load .env and use APP_HOST/APP_PORT
automatically. You can also run Uvicorn directly:
set -a; source .env; set +a
poetry run uvicorn app.main:app --reload --host $APP_HOST --port $APP_PORTGET /api/v1/health
All route management endpoints require the permission configured in
ROUTES_ADMIN_PERMISSION (default: gateway:routes:manage).
GET /api/v1/routesGET /api/v1/routes/{route_id}POST /api/v1/routesPUT /api/v1/routes/{route_id}DELETE /api/v1/routes/{route_id}
Routes are stored in the YAML file configured by ROUTES_CONFIG_PATH
(default: routes.yaml).
Example:
routes:
- id: users
name: users-service
methods: ["GET"]
regex: "^/users/(\\d+)$"
upstream_base_url: "http://users:8000"
rewrite:
regex_uri: ["^/users/(\\d+)$", "/members/\\1"]
auth:
required: true
permission: "users:read"
roles: ["admin"]
priority: 10
enabled: trueNotes:
- Matching uses regex against the request path.
- Routes are sorted by
priority(higher wins). rewrite.regex_uriuses Pythonre.subreplacement syntax.- If any of
auth.required,auth.permission, orauth.rolesis set, the request must have a validAuthorization: Bearer <token>header.
The gateway delegates token validation and permission checks to auth_service.
Configure the endpoints with:
AUTH_SERVICE_BASE_URLAUTH_SERVICE_VALIDATE_PATHAUTH_SERVICE_AUTHORIZE_PATHAUTH_SERVICE_TIMEOUT_SECONDS
The roles check expects a roles claim (string or list) in the validation
response.
Rate limiting is in-memory per process. Configure with:
RATE_LIMIT_ENABLEDRATE_LIMIT_REQUESTSRATE_LIMIT_WINDOW_SECONDSRATE_LIMIT_EXEMPT_PATHSRATE_LIMIT_KEY_HEADER(defaults toX-Forwarded-For)
Key settings are read from .env (see env.example):
- App:
APP_NAME,APP_ENV,APP_HOST,APP_PORT,LOG_LEVEL - API:
API_PREFIX - CORS:
CORS_ALLOW_ORIGINS,CORS_ALLOW_METHODS,CORS_ALLOW_HEADERS,CORS_ALLOW_CREDENTIALS - Auth:
AUTH_SERVICE_* - Rate limit:
RATE_LIMIT_* - Proxy:
ROUTES_CONFIG_PATH,PROXY_TIMEOUT_SECONDS,ROUTES_ADMIN_PERMISSION
poetry run pytestWith coverage:
poetry run pytest --cov=app --cov-report=term-missing --cov-fail-under=85