Gateway API¶
Gateway is the public entrypoint for Engine APIs and forwards execution requests to Orchestrator and Transformers.
Base URL examples:
- Local:
http://localhost:8080 - Cluster:
http://gateway:8080
Main Endpoints¶
Health¶
GET /healthzGET /readyzGET /v1/status(aggregated downstream status)
Transformation¶
POST /v1/transform
Request body:
{
"xml": "<root>Hello</root>",
"xslt": "<xsl:stylesheet version=\"1.0\">...</xsl:stylesheet>"
}
Workflow Invocation¶
Production (ADR 0009): external callers use trigger edge routes only (/v1/api/...). Set GATEWAY_DISABLE_DIRECT_RUN=true so direct run endpoints return 404.
GET|POST|PUT|PATCH|DELETE|HEAD /v1/api/{public_path}— edge routes (kind: api): full URL path must match exactly (e.g./v1/api/orders/create). Paths come from triggergateway_public_pathand/orEDGE_ROUTES_DIR.POST /v1/webhooks/{public_path}— webhooks (kind: webhook): raw body + optional HMAC;response_modesync oraccepted(202 + async orchestrator call).POST /v1/run/{workflow_name}— dev/legacy only whenGATEWAY_DISABLE_DIRECT_RUNis not set.POST /v1/run— legacy: workflow in JSON body (same opt-in).
POST /v1/api/... request body (JSON wrapper or raw XML/text for mutating methods; GET/HEAD use a synthetic <request/> when no body):
{
"xml": "<root><message>Hello</message></root>"
}
Edge route mapping behavior:
- Gateway resolves
method + path(exact match) via merged configuration. - On match, forwards to Orchestrator
POST /run/{workflow}(query string preserved). - Unknown route →
404with explanation indetail. constraints.required_query→400when listed query keys are missing (before orchestrator call).
Trace Proxy¶
GET /v1/tracesGET /v1/traces/{request_id}GET /v1/traces/{request_id}/steps/{step_path}/{kind}
Header Behavior¶
- Accepts and forwards
Authorizationfor workflow run endpoints. - Uses
X-Request-IDfor request-level correlation. - Adds/propagates a correlation header internally to downstream services.
- Route-level
request.add_headers/set_properties(asX-Mesh-Property-*) are forwarded to the orchestrator where relevant.
Error Behavior¶
502when downstream service is unavailable.504on downstream timeout.- Pass-through of orchestrator/transformer error status where applicable.
503when required backend URL is not configured.404for unknown/v1/api/*or/v1/webhooks/*route (or wrongkindon that path).401invalid webhook signature.405whenGATEWAY_VALIDATE_TRIGGERS=trueand the route method is not in the workflowinvocation.http_method.413when body/XML payload exceeds configured maximum size.
Edge Route Configuration¶
Sources (merge)¶
EDGE_ROUTES_DIR(default/app/flows/edge-routes): YAML files*.yamlper route or bulkEdgeRouteConfig.EDGE_ROUTE_CONFIG_JSON: JSON document (same schema as historical config).- Capability registry (optional): dynamic routes; static/file routes win on the same
method+path.
YAML in EDGE_ROUTES_DIR overrides entries from EDGE_ROUTE_CONFIG_JSON for the same method + path.
Other environment variables:
EDGE_ROUTE_CACHE_TTL_SECONDS: loader cache TTL in seconds.ORCHESTRATOR_URLGATEWAY_MAX_XML_BYTESGATEWAY_VALIDATE_TRIGGERS:true/1— validatetarget.require_invocation_http/require_method_matchagainstGET {ORCHESTRATOR_URL}/workflows/http.WORKFLOW_TRIGGER_REFRESH_SECONDS: poll interval for trigger cache.
EdgeRouteConfig Example (JSON or YAML kind: EdgeRouteConfig)¶
Paths are full gateway paths (including /v1/api/...).
{
"api_version": "meshflows.io/v1alpha1",
"kind": "EdgeRouteConfig",
"spec": {
"routes": [
{
"id": "orders-create",
"kind": "api",
"method": "POST",
"path": "/v1/api/orders/create",
"target": { "workflow": "order-create" },
"auth": {
"mode": "oauth2",
"required_scopes": ["orders:write"]
},
"constraints": {
"content_types": ["application/xml", "application/json"],
"max_payload_bytes": 1048576,
"required_headers": ["X-Request-ID"],
"required_query": ["api-version"]
},
"rate_limit": {
"max_requests": 60,
"window_seconds": 60,
"key_from": "subject"
},
"transform": {
"body_to_xml_template": "orders/body-to-xml.liquid"
},
"request": {
"add_headers": { "X-Mesh-Source": "edge" },
"remove_headers": ["X-Internal-Only"],
"set_properties": { "tenant_id_from": "header:X-Tenant-Id" }
},
"response": {
"add_headers": { "X-Mesh-Route-Id": "orders-create", "Cache-Control": "no-store" },
"remove_headers": ["Server"]
}
}
]
}
}
Webhooks (kind: webhook)¶
- Path preferably under
/v1/webhooks/.... webhook.response_mode:accepted→ HTTPack_status(default 202) + fire-and-forget to orchestrator;sync→ waits for orchestrator response.webhook.signature: HMAC-SHA256 or SHA1; header value usuallysha256=<hex>(prefix configurable).- Secret:
secret_refenv:VARor envEDGE_WEBHOOK_SECRET_<ROUTE_ID_UPPER_SNAKE>(normalized route id). webhook.replay_protection: iftimestamp_headercontains a numeric Unix timestamp, max agemax_age_seconds; otherwise no time check (e.g. UUID headers).webhook.idempotency: value from the given header is sent to the orchestrator asX-Idempotency-Key.
Flow policies under flows/policies (evaluate_policies) apply to both /v1/api/* and /v1/webhooks/* (trigger http). See Gateway flow policies for policy types, YAML fields, matching rules, and optional policy bindings on the workflow invocation.
Notes¶
auth.modesupportsnone,token, andoauth2(JWT or API key bearer tokens).rate_limituses a fixed window counter in-process (Redis-backed limiter may apply elsewhere in stack).- Gateway can run in orchestration-only mode where non-essential endpoints are restricted.
- Business execution semantics are owned by Orchestrator; Gateway focuses on routing and edge concerns.
Examples¶
curl -s http://localhost:8080/v1/status
curl -s -X POST http://localhost:8080/v1/run/demo \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"xml":"<root>Hello</root>"}'
REST Client (Cursor/VS Code): zie flows/requests/requests/gateway-edge-routes.http.
HMAC-handtekening genereren (Windows): engine/scripts/gen-webhook-signature.ps1.