mirror of
https://github.com/furyhawk/api_gateway.git
synced 2026-07-20 09:47:59 +00:00
feat: update gateway configuration to support dynamic gateway port and enhance Docker integration
This commit is contained in:
+2
-1
@@ -1,2 +1,3 @@
|
||||
DATAMALL_API_KEY=replace-with-your-lta-datamall-account-key
|
||||
PORT=8000
|
||||
PORT=8067
|
||||
GATEWAY_PORT=8067
|
||||
|
||||
+1
-1
@@ -16,4 +16,4 @@ COPY openapi_json ./openapi_json
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["uv", "run", "uvicorn", "gateway_framework.main:app", "--host", "0.0.0.0", "--port", "8000", "--app-dir", "src"]
|
||||
CMD ["uv", "run", "python", "-m", "gateway_framework.main"]
|
||||
|
||||
@@ -5,6 +5,7 @@ IMAGE_NAME ?= openapi-api-gateway
|
||||
IMAGE_TAG ?= latest
|
||||
CONTAINER_NAME ?= openapi-api-gateway
|
||||
PORT ?= 8000
|
||||
GATEWAY_PORT ?= $(PORT)
|
||||
ENV_FILE ?= .env
|
||||
CONFIG_PROFILE ?= local
|
||||
COMPOSE_FILE ?= docker-compose.dev.yml
|
||||
@@ -46,14 +47,15 @@ run:
|
||||
$(MAKE) stop >/dev/null 2>&1 || true
|
||||
$(CONTAINER_ENGINE) run -d \
|
||||
--name $(CONTAINER_NAME) \
|
||||
-p $(PORT):8000 \
|
||||
-p $(PORT):$(GATEWAY_PORT) \
|
||||
-e GATEWAY_CONFIG_PATH=$(GATEWAY_CONFIG_PATH) \
|
||||
-e GATEWAY_PORT=$(GATEWAY_PORT) \
|
||||
$(RUN_ENV) \
|
||||
$(IMAGE_NAME):$(IMAGE_TAG)
|
||||
@echo "Gateway is running on http://127.0.0.1:$(PORT) using $(GATEWAY_CONFIG_PATH)"
|
||||
@echo "Gateway is running on http://127.0.0.1:$(PORT) using $(GATEWAY_CONFIG_PATH) (bind port $(GATEWAY_PORT))"
|
||||
|
||||
run-local:
|
||||
GATEWAY_CONFIG_PATH=$(GATEWAY_CONFIG_PATH) uv run uvicorn gateway_framework.main:app --host 0.0.0.0 --port $(PORT) --reload --app-dir src
|
||||
GATEWAY_CONFIG_PATH=$(GATEWAY_CONFIG_PATH) GATEWAY_PORT=$(GATEWAY_PORT) uv run python -m gateway_framework.main
|
||||
|
||||
stop:
|
||||
-$(CONTAINER_ENGINE) rm -f $(CONTAINER_NAME)
|
||||
|
||||
@@ -39,7 +39,7 @@ 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` targets the companion backend inside the bundled compose network.
|
||||
- `config/gateway.container.yaml` targets the companion backend inside the bundled compose network, with default `gateway_port: 8067`.
|
||||
4. Run the gateway with the managed environment:
|
||||
|
||||
```bash
|
||||
@@ -49,6 +49,12 @@ 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`.
|
||||
|
||||
@@ -82,6 +88,8 @@ 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.
|
||||
@@ -95,6 +103,7 @@ settings:
|
||||
title: string
|
||||
version: string
|
||||
description: string
|
||||
gateway_port: 8067
|
||||
external_openapi_file: path/to/openapi.json
|
||||
cache_enabled: false
|
||||
cache_ttl_seconds: 30
|
||||
@@ -125,6 +134,7 @@ Notes:
|
||||
- `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`
|
||||
@@ -203,7 +213,8 @@ make stop
|
||||
|
||||
### Useful Variables
|
||||
- `CONTAINER_ENGINE=docker` (or `podman`)
|
||||
- `PORT=8080`
|
||||
- `PORT=8067`
|
||||
- `GATEWAY_PORT=8067`
|
||||
- `IMAGE_NAME=openapi-api-gateway`
|
||||
- `IMAGE_TAG=latest`
|
||||
- `ENV_FILE=.env`
|
||||
@@ -211,7 +222,7 @@ make stop
|
||||
Example:
|
||||
```bash
|
||||
make build CONTAINER_ENGINE=docker IMAGE_TAG=dev
|
||||
make run CONTAINER_ENGINE=docker PORT=8080 ENV_FILE=.env CONFIG_PROFILE=local
|
||||
make run CONTAINER_ENGINE=docker PORT=8080 GATEWAY_PORT=8080 ENV_FILE=.env CONFIG_PROFILE=local
|
||||
```
|
||||
|
||||
## GitHub Packages (GHCR)
|
||||
|
||||
@@ -2,6 +2,7 @@ settings:
|
||||
title: LTA DataMall API Gateway
|
||||
version: 0.2.1
|
||||
description: Configurable gateway for OpenAPI-based upstream services
|
||||
gateway_port: 8067
|
||||
external_openapi_file: openapi_json/lta_datamall_openapi_v0-1-1.json
|
||||
cache_enabled: true
|
||||
cache_ttl_seconds: 30
|
||||
|
||||
@@ -2,6 +2,7 @@ settings:
|
||||
title: LTA DataMall API Gateway
|
||||
version: 0.2.1
|
||||
description: Configurable gateway for a locally running LTA DataMall backend
|
||||
gateway_port: 8067
|
||||
external_openapi_file: openapi_json/lta_datamall_openapi_v0-1-1.json
|
||||
cache_enabled: true
|
||||
cache_ttl_seconds: 30
|
||||
|
||||
@@ -18,5 +18,6 @@ services:
|
||||
- lta-datamall-api
|
||||
environment:
|
||||
GATEWAY_CONFIG_PATH: config/gateway.container.yaml
|
||||
GATEWAY_PORT: ${PORT:-8000}
|
||||
ports:
|
||||
- "${PORT:-8000}:8000"
|
||||
- "${PORT:-8000}:${PORT:-8000}"
|
||||
|
||||
@@ -12,6 +12,7 @@ class GatewaySettings(BaseModel):
|
||||
title: str = "OpenAPI API Gateway"
|
||||
version: str = "0.1.0"
|
||||
description: str = "Configurable API gateway"
|
||||
gateway_port: int = Field(default=8000, ge=1, le=65535)
|
||||
external_openapi_file: str | None = None
|
||||
cache_enabled: bool = False
|
||||
cache_ttl_seconds: float = Field(default=30.0, ge=1.0, le=3600.0)
|
||||
|
||||
@@ -1,3 +1,35 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
import uvicorn
|
||||
|
||||
from .app import create_app
|
||||
from .config import load_gateway_config
|
||||
|
||||
app = create_app()
|
||||
|
||||
|
||||
def _resolve_runtime_port() -> int:
|
||||
override = os.getenv("GATEWAY_PORT") or os.getenv("PORT")
|
||||
if override:
|
||||
try:
|
||||
port = int(override)
|
||||
except ValueError as exc:
|
||||
raise ValueError("GATEWAY_PORT must be an integer") from exc
|
||||
if not 1 <= port <= 65535:
|
||||
raise ValueError("GATEWAY_PORT must be between 1 and 65535")
|
||||
return port
|
||||
|
||||
config_path = os.getenv("GATEWAY_CONFIG_PATH", "config/gateway.yaml")
|
||||
return load_gateway_config(config_path).settings.gateway_port
|
||||
|
||||
|
||||
def run() -> None:
|
||||
host = os.getenv("GATEWAY_HOST", "0.0.0.0")
|
||||
port = _resolve_runtime_port()
|
||||
uvicorn.run("gateway_framework.main:app", host=host, port=port)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
|
||||
@@ -31,6 +31,7 @@ routes:
|
||||
assert "demo" in config.upstreams
|
||||
assert config.routes[0].path == "/api/v1/demo"
|
||||
assert config.upstreams["demo"].port == 8443
|
||||
assert config.settings.gateway_port == 8000
|
||||
|
||||
|
||||
def test_load_gateway_config_unknown_upstream(tmp_path) -> None:
|
||||
@@ -94,4 +95,5 @@ def test_container_gateway_config_matches_local_route_set() -> None:
|
||||
assert {route.path for route in local_config.routes} == {
|
||||
route.path for route in container_config.routes
|
||||
}
|
||||
assert container_config.upstreams["lta_datamall"].resolved_base_url() == "http://lta-datamall-api:8000/"
|
||||
assert local_config.settings.gateway_port == container_config.settings.gateway_port
|
||||
assert container_config.upstreams["lta_datamall"].port is not None
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from gateway_framework.main import _resolve_runtime_port
|
||||
|
||||
|
||||
def test_resolve_runtime_port_from_env(monkeypatch) -> None:
|
||||
monkeypatch.setenv("GATEWAY_PORT", "18080")
|
||||
|
||||
assert _resolve_runtime_port() == 18080
|
||||
|
||||
|
||||
def test_resolve_runtime_port_from_config_when_env_absent(tmp_path, monkeypatch) -> None:
|
||||
monkeypatch.delenv("GATEWAY_PORT", raising=False)
|
||||
monkeypatch.delenv("PORT", raising=False)
|
||||
|
||||
config_file = tmp_path / "gateway.yaml"
|
||||
config_file.write_text(
|
||||
"""
|
||||
settings:
|
||||
gateway_port: 19090
|
||||
upstreams:
|
||||
demo:
|
||||
base_url: https://example.com/
|
||||
routes:
|
||||
- path: /api/v1/demo
|
||||
methods: [GET]
|
||||
upstream: demo
|
||||
""".strip(),
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setenv("GATEWAY_CONFIG_PATH", str(config_file))
|
||||
|
||||
assert _resolve_runtime_port() == 19090
|
||||
Reference in New Issue
Block a user