-
Notifications
You must be signed in to change notification settings - Fork 179
Description
Expected Behavior
When using the Event Handler with REST API Gateway V1 and multi-value query parameters (e.g., ?filter=active&filter=published), the handler should:
- Extract all parameter values in the correct order:
['active', 'published'] - Not duplicate any values
- Match the behavior documented in AWS API Gateway where
multiValueQueryStringParameterscontains all values in order
Current Behavior
The Event Handler duplicates multi-value query parameters.
For example, with the URL ?filter=active&filter=published:
- Expected:
['active', 'published'] - Actual:
['published', 'active', 'published']
This happens, I think, because the converter in packages/event-handler/src/rest/converters.ts (lines 74-86) processes BOTH queryStringParameters AND multiValueQueryStringParameters from the API Gateway V1 event, but according to AWS documentation:
queryStringParameterscontains the last value of each parametermultiValueQueryStringParameterscontains all values for each parameter
When both fields contain the same parameter, the current implementation appends values from both, causing duplication.
Code snippet
Failing E2E test:
// packages/event-handler/tests/e2e/restEventHandler.test.ts (line 206)
it('handles array query parameters', async () => {
const searchQuery = 'test';
const filters = ['active', 'published'];
const response = await fetch(
`${apiUrl}/params/search?q=${searchQuery}&filter=${filters[0]}&filter=${filters[1]}`
);
const data = await response.json();
expect(response.status).toBe(200);
expect(data.query).toBe(searchQuery);
expect(data.filters).toEqual(['active', 'published']); // FAILS
});Handler implementation:
// packages/event-handler/tests/e2e/routers/paramsRouter.ts
paramsRouter.get('/search', ({ req }) => {
const url = new URL(req.url);
const filters = url.searchParams.getAll('filter');
return { filters: filters.length > 0 ? filters : undefined };
});Failing unit test demonstrating the bug:
// Add to packages/event-handler/tests/unit/rest/converters.test.ts after line 299
it('handles same parameter in both queryStringParameters and multiValueQueryStringParameters without duplication', () => {
// Prepare
// This simulates real API Gateway V1 behavior where multi-value query params
// appear in BOTH fields:
// - queryStringParameters contains the LAST value
// - multiValueQueryStringParameters contains ALL values
// Example: ?filter=active&filter=published
const event = {
...baseEvent,
queryStringParameters: {
filter: 'published', // Last value (API Gateway behavior)
},
multiValueQueryStringParameters: {
filter: ['active', 'published'], // All values (API Gateway behavior)
},
};
// Act
const request = proxyEventToWebRequest(event);
// Assess
expect(request).toBeInstanceOf(Request);
const url = new URL(request.url);
// Should NOT have duplicates - should only be ['active', 'published']
// BUG: Currently returns ['published', 'active', 'published'] due to processing both
fields
expect(url.searchParams.getAll('filter')).toEqual(['active', 'published']);
});Steps to Reproduce
- Create a REST API (not HTTP API) using API Gateway V1 with Lambda proxy integration
- Use the Event Handler experimental-rest module
- Send a request with multi-value query parameters:
GET /search?filter=active&filter=published - Extract parameters using url.searchParams.getAll('filter')
- Observe that the array contains duplicates and wrong order:
['published', 'active', 'published']
Alternatively, paste the unit test shown above and run the tests locally
Possible Solution
The converter should skip parameters in queryStringParameters if they exist in multiValueQueryStringParameters, similar to how the header deduplication logic works (lines 61-68).
Proposed fix in packages/event-handler/src/rest/converters.ts:
const url = new URL(path, `${protocol}://${hostname}/`);
// Only process queryStringParameters for params NOT in multiValueQueryStringParameters
for (const [name, value] of Object.entries(
event.queryStringParameters ?? {}
)) {
// Skip if this parameter exists in multiValueQueryStringParameters
if (
value != null &&
!event.multiValueQueryStringParameters?.[name]
) {
url.searchParams.append(name, value);
}
}
// Process multi-value query string parameters (these take precedence)
for (const [name, values] of Object.entries(
event.multiValueQueryStringParameters ?? {}
)) {
for (const value of values ?? []) {
url.searchParams.append(name, value);
}
}Powertools for AWS Lambda (TypeScript) version
latest
AWS Lambda function runtime
22.x
Packaging format used
npm
Execution logs
Metadata
Metadata
Assignees
Labels
Type
Projects
Status