Skip to content

🐛 Use rawQueryString for API Gateway v2 to preserve repeated query params - #1473

Open
alexalligator wants to merge 1 commit into
zappa:masterfrom
alexalligator:fix/apigw-v2-raw-query-string
Open

🐛 Use rawQueryString for API Gateway v2 to preserve repeated query params#1473
alexalligator wants to merge 1 commit into
zappa:masterfrom
alexalligator:fix/apigw-v2-raw-query-string

Conversation

@alexalligator

Copy link
Copy Markdown

Description

API Gateway payload format 2.0 has no multiValueQueryStringParameters and flattens repeated parameters into a comma-joined value in queryStringParameters (?id=1&id=2 => {"id": "1,2"}). process_lambda_payload_v2 read that lossy field, so applications saw a single value "1,2" instead of two, breaking anything relying on repeated parameters (Wagtail choosers, request.GET.getlist, django-filter, DRF).

Build QUERY_STRING from rawQueryString instead, which API Gateway delivers verbatim and already percent-encoded, so it is passed through without urlencode (double-escaping) or unquote (which would destroy a literal & or = inside a value). This also preserves a literal comma in a single value, which queryStringParameters cannot express.

The presence check is "rawQueryString" in event_info rather than truthiness, so an empty query string does not fall through to the legacy path. Invokers other than API Gateway may send a v2-shaped event with no rawQueryString; that fallback now uses doseq=True to match the v1 multi-value branch.

zappa/asgi.py calls the same function, so ASGI apps are fixed too, as are Lambda Function URLs, which use payload format 2.0 regardless of the apigateway_version setting. v1 (REST API) and ALB are unchanged.

This was invisible to the suite because every v2 fixture used "rawQueryString": "" and the only v2 QUERY_STRING assertion checked for "". Adds regression tests at the WSGI, ASGI and handler levels.

GitHub Issues

Closes #1472

…rams

API Gateway payload format 2.0 has no multiValueQueryStringParameters and
flattens repeated parameters into a comma-joined value in
queryStringParameters (?id=1&id=2 => {"id": "1,2"}).
process_lambda_payload_v2 read that lossy field, so applications saw a
single value "1,2" instead of two, breaking anything relying on repeated
parameters (Wagtail choosers, request.GET.getlist, django-filter, DRF).

Build QUERY_STRING from rawQueryString instead, which API Gateway delivers
verbatim and already percent-encoded, so it is passed through without
urlencode (double-escaping) or unquote (which would destroy a literal &
or = inside a value). This also preserves a literal comma in a single
value, which queryStringParameters cannot express.

The presence check is "rawQueryString" in event_info rather than
truthiness, so an empty query string does not fall through to the legacy
path. Invokers other than API Gateway may send a v2-shaped event with no
rawQueryString; that fallback now uses doseq=True to match the v1
multi-value branch.

zappa/asgi.py calls the same function, so ASGI apps are fixed too, as are
Lambda Function URLs, which use payload format 2.0 regardless of the
apigateway_version setting. v1 (REST API) and ALB are unchanged.

This was invisible to the suite because every v2 fixture used
"rawQueryString": "" and the only v2 QUERY_STRING assertion checked for
"". Adds regression tests at the WSGI, ASGI and handler levels.

Closes zappa#1472

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@alexalligator

Copy link
Copy Markdown
Author

Hi, one more thing:

Note that there are existing test failures on main. This PR adds 7 new passing tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API Gateway v2 (HTTP API) collapses repeated query parameters into one comma-joined value

1 participant