Skip to content

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 /healthz
  • GET /readyz
  • GET /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 trigger gateway_public_path and/or EDGE_ROUTES_DIR.
  • POST /v1/webhooks/{public_path}webhooks (kind: webhook): raw body + optional HMAC; response_mode sync or accepted (202 + async orchestrator call).
  • POST /v1/run/{workflow_name}dev/legacy only when GATEWAY_DISABLE_DIRECT_RUN is 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 → 404 with explanation in detail.
  • constraints.required_query400 when listed query keys are missing (before orchestrator call).

Trace Proxy

  • GET /v1/traces
  • GET /v1/traces/{request_id}
  • GET /v1/traces/{request_id}/steps/{step_path}/{kind}

Header Behavior

  • Accepts and forwards Authorization for workflow run endpoints.
  • Uses X-Request-ID for request-level correlation.
  • Adds/propagates a correlation header internally to downstream services.
  • Route-level request.add_headers / set_properties (as X-Mesh-Property-*) are forwarded to the orchestrator where relevant.

Error Behavior

  • 502 when downstream service is unavailable.
  • 504 on downstream timeout.
  • Pass-through of orchestrator/transformer error status where applicable.
  • 503 when required backend URL is not configured.
  • 404 for unknown /v1/api/* or /v1/webhooks/* route (or wrong kind on that path).
  • 401 invalid webhook signature.
  • 405 when GATEWAY_VALIDATE_TRIGGERS=true and the route method is not in the workflow invocation.http_method.
  • 413 when body/XML payload exceeds configured maximum size.

Edge Route Configuration

Sources (merge)

  1. EDGE_ROUTES_DIR (default /app/flows/edge-routes): YAML files *.yaml per route or bulk EdgeRouteConfig.
  2. EDGE_ROUTE_CONFIG_JSON: JSON document (same schema as historical config).
  3. 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_URL
  • GATEWAY_MAX_XML_BYTES
  • GATEWAY_VALIDATE_TRIGGERS: true / 1 — validate target.require_invocation_http / require_method_match against GET {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 → HTTP ack_status (default 202) + fire-and-forget to orchestrator; sync → waits for orchestrator response.
  • webhook.signature: HMAC-SHA256 or SHA1; header value usually sha256=<hex> (prefix configurable).
  • Secret: secret_ref env:VAR or env EDGE_WEBHOOK_SECRET_<ROUTE_ID_UPPER_SNAKE> (normalized route id).
  • webhook.replay_protection: if timestamp_header contains a numeric Unix timestamp, max age max_age_seconds; otherwise no time check (e.g. UUID headers).
  • webhook.idempotency: value from the given header is sent to the orchestrator as X-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.mode supports none, token, and oauth2 (JWT or API key bearer tokens).
  • rate_limit uses 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.