Skip to main content

Multi-Gateway Orchestration

STOA's Control Plane orchestrates multiple API gateways through a unified Adapter pattern. Register any supported gateway, and the Control Plane handles API synchronization, policy enforcement, and consumer provisioning across all of them.

Architecture​

Supported Gateways​

GatewayTypeStorageAdmin APIAdapter Status
STOARust, axumIn-memoryREST (/admin/*)Full support
KongLua, OpenRestyDB-less YAMLREST (:8001)Full support
GraviteeJavaMongoDB + ESREST (:8083)Full support
webMethodsJavaElasticsearchREST (:5555)Full support (16/16 methods)

Adapter Interface​

Every gateway adapter implements 16 abstract methods organized in 5 categories:

Lifecycle (3 methods)​

MethodPurposeReturns
health_check()Verify gateway connectivityAdapterResult
connect()Initialize connection/sessionNone
disconnect()Clean up resourcesNone

API Management (3 methods)​

MethodPurposeReturns
sync_api(api_spec, tenant_id)Create or update an API routeAdapterResult
delete_api(api_id)Remove an API routeAdapterResult
list_apis()List all managed APIslist[dict]

Policy Management (3 methods)​

MethodPurposeReturns
upsert_policy(policy_spec)Create or update a policy (rate limit, CORS)AdapterResult
delete_policy(policy_id)Remove a policyAdapterResult
list_policies()List all managed policieslist[dict]

Consumer Management (3 methods)​

MethodPurposeReturns
provision_application(app_spec)Register a consumer with credentialsAdapterResult
deprovision_application(app_id)Remove a consumerAdapterResult
list_applications()List all managed consumerslist[dict]

Extended (4 methods, gateway-specific)​

MethodPurposeSupported By
upsert_auth_server(auth_spec)Configure OIDC providerwebMethods
upsert_strategy(strategy_spec)Set auth strategywebMethods
upsert_scope(scope_spec)Define OAuth scopeswebMethods
upsert_alias(alias_spec)Configure endpoint aliaswebMethods
apply_config(config_spec)Apply full configurationwebMethods
export_archive()Export gateway backupwebMethods

Unsupported methods return AdapterResult(success=False, error="Not supported by <gateway>").

AdapterResult​

All adapter methods return a standardized result:

@dataclass
class AdapterResult:
success: bool
resource_id: str | None = None
data: dict | None = None
error: str | None = None

Gateway Registration​

Register gateways via the Control Plane API or CRD:

Via API​

Configure your environment

The examples below use environment variables. Set them for your STOA instance:

export STOA_API_URL="https://api.gostoa.dev"       # Replace with your domain
export STOA_AUTH_URL="https://auth.gostoa.dev" # Keycloak OIDC provider
export STOA_GATEWAY_URL="https://mcp.gostoa.dev" # MCP Gateway endpoint

Self-hosted? Replace gostoa.dev with your domain.

curl -X POST "${STOA_API_URL}/v1/gateways" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "kong-production",
"display_name": "Kong Production (GRA)",
"gateway_type": "kong",
"base_url": "http://kong-admin:8001",
"environment": "prod",
"capabilities": ["rest", "rate_limiting"]
}'

Via CRD​

apiVersion: gostoa.dev/v1alpha1
kind: GatewayInstance
metadata:
name: kong-production
namespace: stoa-system
spec:
displayName: Kong Production (GRA)
gatewayType: kong
environment: prod
baseUrl: http://kong-admin:8001
capabilities: [rest, rate_limiting]

Gateway Types​

Valid gateway_type values:

TypeDescription
stoaSTOA Gateway (generic)
stoa_edge_mcpSTOA in edge-mcp mode
stoa_sidecarSTOA in sidecar mode
stoa_proxySTOA in proxy mode
stoa_shadowSTOA in shadow mode
kongKong (DB-less)
graviteeGravitee APIM v4
webmethodsSoftware AG webMethods
apigeeGoogle Apigee
aws_apigatewayAWS API Gateway

Per-Gateway Details​

STOA Gateway (Rust)​

AspectDetail
Admin APIPOST /admin/apis, POST /admin/policies, GET /admin/health
AuthBearer token (admin_api_token)
StorageIn-memory (Control Plane is source of truth)
Idempotencysync_api and upsert_policy are both upserts
Key behaviorAll state lost on restart; CP API re-syncs automatically
# Health check
curl "${STOA_GATEWAY_URL}/admin/health" \
-H "Authorization: Bearer ${ADMIN_TOKEN}"

Kong (DB-less)​

AspectDetail
Admin APIGET /services, GET /plugins, POST /config
AuthKong-Admin-Token header
StorageDeclarative YAML via POST /config (atomic reload)
State patternRead current β†’ merge changes β†’ POST full config
Config version_format_version: "3.0" required

Kong DB-less mode makes the Admin API read-only for individual writes. All mutations follow the read-merge-post pattern:

1. GET /services + /plugins + /consumers β†’ current state
2. Merge desired change (upsert by name/tag)
3. POST /config with full declarative payload β†’ atomic reload

Gravitee (APIM v4)​

AspectDetail
Management API/management/v2/environments/DEFAULT/apis
AuthBasic auth (configurable)
StorageMongoDB + Elasticsearch (full CRUD)
API lifecycleCREATED β†’ PUBLISHED β†’ STARTED β†’ DEPLOYED
PlansRate limiting via Plans with flows (not standalone policies)

Gravitee APIs require explicit lifecycle transitions:

1. POST /apis (create, V4 definition)
2. POST /apis/{id}/_start (start)
3. POST /apis/{id}/deployments (deploy)

webMethods (Software AG)​

AspectDetail
Admin API/rest/apigateway/*
AuthBasic auth (Administrator:manage)
StorageElasticsearch (internal)
Feature setFull 16/16 methods (most complete adapter)
OpenAPI importOnly 3.0.x supported (not 3.1.0)

webMethods is the most feature-complete adapter, supporting OIDC integration, endpoint aliases, configuration management, and full backup/export.

Sync Workflow​

When you create or update an API in the Control Plane, it syncs to all bound gateways:

For multi-gateway setups, the Control Plane syncs to each bound gateway:

Adding a New Gateway Adapter​

  1. Copy control-plane-api/src/adapters/template/ to adapters/<new_gateway>/
  2. Implement all 16 abstract methods in adapter.py
  3. Create spec translation functions in mappers.py
  4. Register in adapters/registry.py
  5. Add the type to the gateway_type_enum database migration
  6. Write tests (~30+ unit tests with mocked HTTP calls)

Adapter Contract Rules​

  • All methods must be idempotent (calling twice produces the same result)
  • Return AdapterResult(success=False, error="...") for failures; never raise exceptions
  • Use httpx.AsyncClient for HTTP calls (async, connection pooling)
  • Log warnings for non-critical failures (e.g., plan not subscribable)

Troubleshooting​

ProblemCauseFix
sync_api returns 404Gateway not registeredRegister via API or CRD first
Kong config reload failsInvalid service in payloadAll-or-nothing: one bad service breaks the reload
Gravitee API not reachableAPI not started/deployedRun the full lifecycle: create β†’ plan β†’ publish β†’ deploy β†’ start
webMethods import failsOpenAPI 3.1.0 specConvert to 3.0.3: sed 's/3.1.0/3.0.3/'
Adapter returns "Not supported"Extended method on non-webMethodsExpected; only webMethods supports all 16 methods