Skip to content

fix(apigateway): resolve v2 API region across all regions for data-plane dispatch#1906

Open
tirthachetry-zoho wants to merge 2 commits into
floci-io:mainfrom
tirthachetry-zoho:fix/apigateway-v2-cross-region-data-plane
Open

fix(apigateway): resolve v2 API region across all regions for data-plane dispatch#1906
tirthachetry-zoho wants to merge 2 commits into
floci-io:mainfrom
tirthachetry-zoho:fix/apigateway-v2-cross-region-data-plane

Conversation

@tirthachetry-zoho

@tirthachetry-zoho tirthachetry-zoho commented Jul 18, 2026

Copy link
Copy Markdown

Unsigned data-plane requests (browser/frontend) carry no SigV4 Authorization header, so the region resolves to the default (us-east-1). The v2 dispatch detection previously called getApi(region, apiId) with the unresolved region, so a v2 API created in another region (e.g. eu-west-1) was never detected and fell through to v1 handling, failing with
'Invalid API id specified' (404).

Resolve the region first via ApiGatewayV2Service.resolveApiRegion (which scans all stored API keys), then check isV2 using the resolved region. Add ApiGatewayV2Service.apiExists(region, apiId) to detect a v2 API that lives in the same/default region.

Fixes #1902

Summary

Type of change

  • Bug fix (fix:)
  • New feature (feat:)
  • Breaking change (feat!: or fix!:)
  • Docs / chore

AWS Compatibility

Checklist

  • ./mvnw test passes locally
  • New or updated integration test added
  • Commit messages follow Conventional Commits

…ane dispatch

Unsigned data-plane requests (browser/frontend) carry no SigV4
Authorization header, so the region resolves to the default
(us-east-1). The v2 dispatch detection previously called
getApi(region, apiId) with the unresolved region, so a v2 API
created in another region (e.g. eu-west-1) was never detected
and fell through to v1 handling, failing with
'Invalid API id specified' (404).

Resolve the region first via ApiGatewayV2Service.resolveApiRegion
(which scans all stored API keys), then check isV2 using the
resolved region. Add ApiGatewayV2Service.apiExists(region, apiId)
to detect a v2 API that lives in the same/default region.

Fixes floci-io#1902
@greptile-apps

greptile-apps Bot commented Jul 18, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a bug where unsigned (browser/frontend) data-plane requests to v2 HTTP APIs created in a non-default region would always receive a 404 "Invalid API id specified" response. The root cause was that the region resolved to the default (us-east-1) when no SigV4 Authorization header was present, and the v2 dispatch check used that unresolved region.

  • Adds ApiGatewayV2Service.resolveApiRegion (mirroring the existing v1 resolveRestApiRegion) to scan all stored API keys and locate the correct region, and apiExists for same-region detection; both are used in dispatch to correctly set v2Region before forwarding to dispatchV2.
  • Fixes the previously hardcoded us-east-1 in buildV2ProxyEvent's requestContext.domainName field by threading the resolved region through the call chain.
  • Adds an ordered QuarkusTest (ApiGatewayV2CrossRegionDataPlaneReproTest) that reproduces the issue end-to-end and asserts the fixed behaviour.

Confidence Score: 5/5

Safe to merge — the region-resolution logic is correct for all three dispatch cases (cross-region, same-region, and non-v2), the hardcoded domain fix is straightforward, and the new integration test reproduces and validates the reported failure.

All three dispatch scenarios (API in a different region, API in the default region, API not a v2 at all) are correctly handled by the resolveApiRegion + apiExists combination. The buildV2ProxyEvent domainName fix is a clean one-line change. Existing path-parameter tests are updated without logic changes, and the new QuarkusTest exercises the exact failure path from the issue report.

No files require special attention.

Important Files Changed

Filename Overview
src/main/java/io/github/hectorvent/floci/services/apigateway/ApiGatewayExecuteController.java Core dispatch logic updated: replaces the try/catch getApi call with resolveApiRegion + apiExists to correctly detect and route v2 APIs regardless of whether the request carried a SigV4 region; also fixes the hardcoded us-east-1 in buildV2ProxyEvent's domainName.
src/main/java/io/github/hectorvent/floci/services/apigatewayv2/ApiGatewayV2Service.java Adds apiExists (single store lookup) and resolveApiRegion (full key scan with endsWith filter) — both correctly account for the region::apiId key format and handle all dispatch cases.
src/test/java/io/github/hectorvent/floci/services/apigatewayv2/ApiGatewayV2CrossRegionDataPlaneReproTest.java New end-to-end QuarkusTest that reproduces #1902 by creating a v2 API in eu-west-1 then invoking its execute-api URL without an Authorization header; assertions confirm the fix eliminates the 404 'Invalid API id specified' error.
src/test/java/io/github/hectorvent/floci/services/apigateway/BuildV2ProxyEventPathParametersTest.java Mechanical update to pass the new region parameter (us-east-1) to buildV2ProxyEvent in all three existing test cases; no logic changes.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Browser as Browser (no Auth header)
    participant Controller as ApiGatewayExecuteController
    participant RegionResolver as RegionResolver
    participant V2Service as ApiGatewayV2Service

    Browser->>Controller: "GET /execute-api/{apiId}/$default/{path}"
    Controller->>RegionResolver: resolveRegion(headers)
    RegionResolver-->>Controller: "us-east-1" (default, no SigV4)

    Note over Controller,V2Service: NEW: resolve actual v2 region
    Controller->>V2Service: resolveApiRegion("us-east-1", apiId)
    V2Service->>V2Service: apiStore.get("us-east-1::apiId") → empty
    V2Service->>V2Service: scan keys → finds "eu-west-1::apiId"
    V2Service-->>Controller: "eu-west-1"

    Controller->>Controller: "isV2 = true (v2Region != region)"
    Controller->>Controller: "dispatchV2(..., v2Region="eu-west-1")"
    Controller->>V2Service: findMatchingRoute("eu-west-1", apiId, ...)
    V2Service-->>Controller: Route matched

    Note over Controller: buildV2ProxyEvent uses "eu-west-1"<br/>instead of hardcoded "us-east-1"
    Controller-->>Browser: 200 / 502 (not 404 "Invalid API id specified")
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Browser as Browser (no Auth header)
    participant Controller as ApiGatewayExecuteController
    participant RegionResolver as RegionResolver
    participant V2Service as ApiGatewayV2Service

    Browser->>Controller: "GET /execute-api/{apiId}/$default/{path}"
    Controller->>RegionResolver: resolveRegion(headers)
    RegionResolver-->>Controller: "us-east-1" (default, no SigV4)

    Note over Controller,V2Service: NEW: resolve actual v2 region
    Controller->>V2Service: resolveApiRegion("us-east-1", apiId)
    V2Service->>V2Service: apiStore.get("us-east-1::apiId") → empty
    V2Service->>V2Service: scan keys → finds "eu-west-1::apiId"
    V2Service-->>Controller: "eu-west-1"

    Controller->>Controller: "isV2 = true (v2Region != region)"
    Controller->>Controller: "dispatchV2(..., v2Region="eu-west-1")"
    Controller->>V2Service: findMatchingRoute("eu-west-1", apiId, ...)
    V2Service-->>Controller: Route matched

    Note over Controller: buildV2ProxyEvent uses "eu-west-1"<br/>instead of hardcoded "us-east-1"
    Controller-->>Browser: 200 / 502 (not 404 "Invalid API id specified")
Loading

Reviews (2): Last reviewed commit: "fix(apigateway): use resolved region for..." | Re-trigger Greptile

Address PR review feedback on floci-io#1906:

- buildV2ProxyEvent hardcoded us-east-1 in requestContext.domainName, so
  cross-region v2 Lambda invocations (now reachable after the dispatch fix)
  received a wrong domain. Thread the resolved region through and build the
  domain as {apiId}.execute-api.{region}.amazonaws.com.
- Update the repro test Javadoc, which still described the pre-fix buggy
  behaviour and contradicted the actual assertions.
- Update BuildV2ProxyEventPathParametersTest call sites for the new signature.
@hectorvent hectorvent added bug Something isn't working apigatewayv2 Amazon API Gateway v2 (HTTP/WebSocket) labels Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apigatewayv2 Amazon API Gateway v2 (HTTP/WebSocket) bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Unable to access floci apigatewayv2 url

4 participants