From 36ff9ed2f03b070151cc00311d85433fcc621d04 Mon Sep 17 00:00:00 2001 From: Dale Race Date: Wed, 3 Aug 2022 17:33:42 -0600 Subject: [PATCH] Support multiple of same query string for LambdaProxyIntegrationEventV2 --- .../LambdaProxyIntegrationEventV2.js | 5 +++-- ...rseMultiValueQueryStringParameters.test.js | 2 ++ ...eQueryStringParametersForPayloadV2.test.js | 22 +++++++++++++++++++ src/utils/index.js | 1 + .../parseQueryStringParametersForPayloadV2.js | 22 +++++++++++++++++++ 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/utils/__tests__/parseQueryStringParametersForPayloadV2.test.js create mode 100644 src/utils/parseQueryStringParametersForPayloadV2.js diff --git a/src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js b/src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js index 6e315f3c0..2e3e85aed 100644 --- a/src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +++ b/src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js @@ -7,11 +7,12 @@ import { lowerCaseKeys, nullIfEmpty, parseHeaders, + parseQueryStringParametersForPayloadV2, } from '../../../utils/index.js' const { isArray } = Array const { parse } = JSON -const { assign, entries, fromEntries } = Object +const { assign, entries } = Object // https://www.serverless.com/framework/docs/providers/aws/events/http-api/ // https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html @@ -142,7 +143,7 @@ export default class LambdaProxyIntegrationEventV2 { isBase64Encoded: false, pathParameters: nullIfEmpty(pathParams), queryStringParameters: this.#request.url.search - ? fromEntries(Array.from(this.#request.url.searchParams)) + ? parseQueryStringParametersForPayloadV2(this.#request.url.searchParams) : null, rawPath: this.#request.url.pathname, rawQueryString: this.#request.url.searchParams.toString(), diff --git a/src/utils/__tests__/parseMultiValueQueryStringParameters.test.js b/src/utils/__tests__/parseMultiValueQueryStringParameters.test.js index 296a6420a..44c120414 100644 --- a/src/utils/__tests__/parseMultiValueQueryStringParameters.test.js +++ b/src/utils/__tests__/parseMultiValueQueryStringParameters.test.js @@ -41,6 +41,7 @@ const tests = [ description: 'multiple parameters, same keys', expected: { foo: 'foobar' }, expectedMulti: { foo: ['test', 'foobar'] }, + expectedV2: { foo: 'test,foobar' }, param: 'foo=test&foo=foobar', }, @@ -55,6 +56,7 @@ const tests = [ description: 'multiple parameters, same keys, same values', expected: { foo: 'test' }, expectedMulti: { foo: ['test', 'test'] }, + expectedV2: { foo: 'test,test' }, param: 'foo=test&foo=test', }, diff --git a/src/utils/__tests__/parseQueryStringParametersForPayloadV2.test.js b/src/utils/__tests__/parseQueryStringParametersForPayloadV2.test.js new file mode 100644 index 000000000..240eaaa7e --- /dev/null +++ b/src/utils/__tests__/parseQueryStringParametersForPayloadV2.test.js @@ -0,0 +1,22 @@ +import assert from 'node:assert' + +// uses the same tests as parseMultiValueQueryStringParameters +import tests from './parseMultiValueQueryStringParameters.test.js' +import parseQueryStringParametersForPayloadV2 from '../parseQueryStringParametersForPayloadV2.js' +import { BASE_URL_PLACEHOLDER } from '../../config/index.js' + +describe('parseQueryStringParametersForPayloadV2', () => { + tests.forEach(({ description, expected, expectedV2, param }) => { + const url = `/foo?${param}` + const { searchParams } = new URL(url, BASE_URL_PLACEHOLDER) + + it(`should return ${description}`, () => { + const result = parseQueryStringParametersForPayloadV2(searchParams) + if (expectedV2) { + assert.deepEqual(result, expectedV2) + } else { + assert.deepEqual(result, expected) + } + }) + }) +}) diff --git a/src/utils/index.js b/src/utils/index.js index 82f35b51c..cab0628ad 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -9,6 +9,7 @@ export { default as parseHeaders } from './parseHeaders.js' export { default as parseMultiValueHeaders } from './parseMultiValueHeaders.js' export { default as parseMultiValueQueryStringParameters } from './parseMultiValueQueryStringParameters.js' export { default as parseQueryStringParameters } from './parseQueryStringParameters.js' +export { default as parseQueryStringParametersForPayloadV2 } from './parseQueryStringParametersForPayloadV2.js' export { default as splitHandlerPathAndName } from './splitHandlerPathAndName.js' export { default as checkDockerDaemon } from './checkDockerDaemon.js' export { default as checkGoVersion } from './checkGoVersion.js' diff --git a/src/utils/parseQueryStringParametersForPayloadV2.js b/src/utils/parseQueryStringParametersForPayloadV2.js new file mode 100644 index 000000000..f05192e8e --- /dev/null +++ b/src/utils/parseQueryStringParametersForPayloadV2.js @@ -0,0 +1,22 @@ +/** + * + * @description Instead of using `multiValueQueryStringParameters` API Gateway HTTP API combines + * duplicate query string keys with commas in the `queryStringParameters` field. + * https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html + * + * @param { URLSearchParams } searchParams + */ +export default function parseQueryStringParametersForPayloadV2(searchParams) { + const keyValuePairs = Array.from(searchParams) + + if (keyValuePairs.length === 0) { + return null + } + + return keyValuePairs.reduce((previousValue, [key, value]) => { + if (!previousValue[key]) { + return { ...previousValue, [key]: value } + } + return { ...previousValue, [key]: [previousValue[key], value].join(',') } + }, {}) +}