mirror of
https://github.com/furyhawk/api_gateway.git
synced 2026-07-21 10:16:49 +00:00
239 lines
8.3 KiB
Markdown
239 lines
8.3 KiB
Markdown
# OpenAPI API Gateway Framework
|
|
|
|
This repository now includes a lightweight, configurable API gateway framework built with FastAPI.
|
|
|
|
## What It Provides
|
|
- Dynamic gateway routes loaded from YAML (`config/gateway.yaml`)
|
|
- Configurable upstream targets and per-upstream timeout settings
|
|
- OpenAPI docs for gateway endpoints via FastAPI (`/docs`)
|
|
- Optional serving of an external OpenAPI contract (`/openapi/external.json`)
|
|
- Administrative portal at `/admin/portal`
|
|
- Runtime configuration editor via admin endpoints
|
|
- API key creation/list/revocation with optional route protection
|
|
- Built-in management endpoints:
|
|
- `GET /healthz`
|
|
- `GET /readyz`
|
|
- `GET /admin/routes`
|
|
|
|
## Project Structure
|
|
- `src/gateway_framework/app.py`: app factory and dynamic route registration
|
|
- `src/gateway_framework/proxy.py`: request forwarding/proxy logic
|
|
- `src/gateway_framework/config.py`: config schema and loader
|
|
- `src/gateway_framework/main.py`: ASGI entrypoint
|
|
- `src/gateway_framework/static/admin/`: scalable portal frontend assets (`index.html`, `styles.css`, `app.js`)
|
|
- `config/gateway.yaml`: route and upstream configuration
|
|
- `openapi_json/lta_datamall_openapi_v0-1-1.json`: external OpenAPI contract
|
|
|
|
## Quick Start
|
|
1. Install `uv` if not already installed:
|
|
|
|
```bash
|
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
```
|
|
|
|
2. Sync dependencies and create the project virtual environment:
|
|
|
|
```bash
|
|
uv sync
|
|
```
|
|
|
|
3. Choose a gateway profile:
|
|
- `config/gateway.yaml` targets a locally running companion backend on `127.0.0.1:8068`.
|
|
- `config/gateway.container.yaml` uses `GATEWAY_UPSTREAM_HOST` for host-container networking and defaults to `host.docker.internal` (set `GATEWAY_UPSTREAM_HOST=host.containers.internal` for Podman), with default `gateway_port: 8067`.
|
|
4. Run the gateway with the managed environment:
|
|
|
|
```bash
|
|
make run-local CONFIG_PROFILE=local
|
|
```
|
|
|
|
5. Open the docs:
|
|
- `http://127.0.0.1:8000/docs`
|
|
|
|
To run on a different gateway port, pass `GATEWAY_PORT`:
|
|
|
|
```bash
|
|
make run-local CONFIG_PROFILE=local GATEWAY_PORT=8088
|
|
```
|
|
|
|
## Companion Backend Integration
|
|
This gateway is a good front door for the companion backend at `furyhawk/lta_datamall_api`.
|
|
|
|
The gateway now ships with two explicit upstream profiles:
|
|
- `config/gateway.yaml` for a local backend on `http://127.0.0.1:8068`
|
|
- `config/gateway.container.yaml` for the compose service `http://lta-datamall-api:8000`
|
|
|
|
Both profiles are aligned to the companion backend's published route surface:
|
|
- public route prefix: `/api/v1`
|
|
- backend health endpoints remain available at `/healthz` and `/readyz`
|
|
|
|
One-command profile selection:
|
|
- Local host pairing: `make run-local CONFIG_PROFILE=local`
|
|
- Containerized gateway: `make run CONFIG_PROFILE=container`
|
|
- Route parity check against the running companion backend OpenAPI: `make check-companion-parity CONFIG_PROFILE=local`
|
|
|
|
Suggested local pairing workflow:
|
|
1. Run `furyhawk/lta_datamall_api` on port `8068`.
|
|
2. Start this gateway with `make run-local CONFIG_PROFILE=local`.
|
|
3. Use this gateway for edge concerns such as admin config editing, gateway API keys, and response caching while the companion backend owns the LTA DataMall domain logic.
|
|
|
|
## Integrated Dev Compose Workflow
|
|
Use the bundled compose file when you want this repo to start both the gateway and the companion backend together.
|
|
|
|
1. Create `.env` from `.env.example` and set `DATAMALL_API_KEY`.
|
|
2. Start the stack:
|
|
|
|
```bash
|
|
make compose-up
|
|
```
|
|
|
|
3. Open the gateway at `http://127.0.0.1:8000`.
|
|
|
|
If you use the repository defaults from `.env.example`, the gateway is exposed on port `8067`.
|
|
|
|
Notes:
|
|
- `make compose-up` starts the companion backend first, checks its live `/openapi.json`, then starts the gateway.
|
|
- The compose workflow uses Docker Compose because the companion backend is built directly from its Git repository.
|
|
- Tail logs with `make compose-logs` and stop the stack with `make compose-down`.
|
|
|
|
## Configuration Model
|
|
`config/gateway.yaml` uses this model:
|
|
|
|
```yaml
|
|
settings:
|
|
title: string
|
|
version: string
|
|
description: string
|
|
gateway_port: 8067
|
|
external_openapi_file: path/to/openapi.json
|
|
cache_enabled: false
|
|
cache_ttl_seconds: 30
|
|
cache_max_entries: 500
|
|
require_api_key: false
|
|
api_keys_file: config/api_keys.json
|
|
admin_api_key_env: ADMIN_API_KEY
|
|
|
|
upstreams:
|
|
service_name:
|
|
base_url: https://service.example.com/
|
|
port: 8443
|
|
timeout_seconds: 15
|
|
|
|
routes:
|
|
- path: /api/v1/resource
|
|
methods: [GET, POST]
|
|
upstream: service_name
|
|
upstream_path: /v2/resource
|
|
strip_prefix: /api
|
|
summary: Optional operation summary
|
|
tags: [Gateway]
|
|
operation_id: gateway_resource_get
|
|
```
|
|
|
|
Notes:
|
|
- `path` is the public gateway path.
|
|
- `upstream_path` overrides forwarded path.
|
|
- `strip_prefix` removes a leading path segment before forwarding.
|
|
- `port` overrides the upstream URL port without changing the host or scheme.
|
|
- `settings.gateway_port` controls the gateway listen port unless `GATEWAY_PORT` (or `PORT`) is set.
|
|
|
|
## Administrative Portal and Dashboard
|
|
- Admin UI: `GET /admin/portal`
|
|
- Admin static assets: `GET /admin/portal/assets/*`
|
|
- Admin summary: `GET /admin/dashboard`
|
|
- Get config YAML: `GET /admin/config`
|
|
- Save config YAML: `PUT /admin/config`
|
|
- List API keys: `GET /admin/api-keys`
|
|
- Create API key: `POST /admin/api-keys` with body `{"name":"client-name"}`
|
|
- Revoke API key: `DELETE /admin/api-keys/{key_id}`
|
|
- Cache status: `GET /admin/cache`
|
|
- Invalidate cache by route/query fragment: `POST /admin/cache/invalidate`
|
|
- Clear all cache entries: `DELETE /admin/cache`
|
|
|
|
Optional admin auth:
|
|
- Set environment variable `ADMIN_API_KEY` before startup.
|
|
- Send header `x-admin-key: <your-admin-key>` to admin endpoints.
|
|
|
|
## API Key Protection for Gateway Routes
|
|
- Enable gateway key checks by setting `settings.require_api_key: true`.
|
|
- Clients then must send `x-api-key: <key>` on proxied route requests.
|
|
- Create keys from the admin portal or `POST /admin/api-keys`.
|
|
|
|
## Response Cache
|
|
- Enable cache with `settings.cache_enabled: true`.
|
|
- Configure TTL with `settings.cache_ttl_seconds`.
|
|
- Configure memory bound with `settings.cache_max_entries`.
|
|
- Cache currently applies to proxied `GET`/`HEAD` responses with `2xx` status.
|
|
- Gateway adds `x-gateway-cache: MISS` for first fetch and `x-gateway-cache: HIT` for cached responses.
|
|
- Admin invalidation payload example:
|
|
- `{"path": "/api/v1/bus-arrival", "method": "GET", "query_contains": "BusStopCode=12345"}`
|
|
|
|
## Scaling and Configurability Guidance
|
|
- Add routes through config, not code, for repeatable deployments.
|
|
- Split large configurations into environment-specific files and set `GATEWAY_CONFIG_PATH`.
|
|
- Keep route changes backward compatible (`/api/v1` stability) for client safety.
|
|
- Define explicit timeout values per upstream to isolate slow dependencies.
|
|
|
|
## Next Steps
|
|
- Add auth/rate limiting middleware for production.
|
|
- Add OpenAPI linting in CI (for example, Redocly CLI).
|
|
- Add contract tests for every configured route.
|
|
|
|
## Common uv Commands
|
|
- Run tests: `uv run pytest`
|
|
- Run lint: `uv run ruff check .`
|
|
- Add dependency: `uv add <package>`
|
|
- Add dev dependency: `uv add --dev <package>`
|
|
|
|
## Container (Docker or Podman) + Makefile
|
|
The repository includes a containerized workflow via `Dockerfile` and `Makefile`.
|
|
|
|
### Prerequisites
|
|
- Install either Docker or Podman.
|
|
- By default, Makefile uses Podman when available; otherwise Docker.
|
|
|
|
### Build Image
|
|
```bash
|
|
make build
|
|
```
|
|
|
|
### Run Container
|
|
```bash
|
|
make run CONFIG_PROFILE=local
|
|
```
|
|
|
|
Gateway will be available at `http://127.0.0.1:8000`.
|
|
|
|
Use `CONFIG_PROFILE=container` when the upstream backend is running inside the compose network.
|
|
|
|
### Stop and Inspect
|
|
```bash
|
|
make logs
|
|
make stop
|
|
```
|
|
|
|
### Useful Variables
|
|
- `CONTAINER_ENGINE=docker` (or `podman`)
|
|
- `PORT=8067`
|
|
- `GATEWAY_PORT=8067`
|
|
- `GATEWAY_UPSTREAM_HOST=host.docker.internal` (set to `host.containers.internal` for Podman host networking)
|
|
- `IMAGE_NAME=openapi-api-gateway`
|
|
- `IMAGE_TAG=latest`
|
|
- `ENV_FILE=.env`
|
|
|
|
Example:
|
|
```bash
|
|
make build CONTAINER_ENGINE=docker IMAGE_TAG=dev
|
|
make run CONTAINER_ENGINE=docker PORT=8080 GATEWAY_PORT=8080 ENV_FILE=.env CONFIG_PROFILE=local
|
|
```
|
|
|
|
## GitHub Packages (GHCR)
|
|
- Automated image publishing is configured in `.github/workflows/release-image.yml`.
|
|
- On push of a release tag (for example `v0.2.1`), CI builds and pushes:
|
|
- `ghcr.io/furyhawk/api_gateway:v0.2.1`
|
|
- `ghcr.io/furyhawk/api_gateway:latest`
|
|
|
|
Pull example:
|
|
```bash
|
|
docker pull ghcr.io/furyhawk/api_gateway:v0.2.1
|
|
```
|