Skip to content

Commit 2ec64c9

Browse files
author
Daniel Bot
committed
fix: handle arrays with undefined/null values for HTP requests with query params
1 parent a751d84 commit 2ec64c9

File tree

2 files changed

+53
-11
lines changed

2 files changed

+53
-11
lines changed

src/openapi-lambda-adapters.test.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { APIGatewayProxyStructuredResultV2, Context } from 'aws-lambda'
22
import { AxiosRequestConfig } from 'axios'
33
import { AxiosError, HttpMethod, Operation } from 'openapi-client-axios'
4-
import { convertAxiosToApiGw, convertApiGwToAxios } from './openapi-lambda-adapters'
4+
import { convertApiGwToAxios, convertAxiosToApiGw } from './openapi-lambda-adapters'
55

66
describe('Adapt axios request/response to AWS Lambda Proxy Event/Response', () => {
77

@@ -251,6 +251,36 @@ describe('Adapt axios request/response to AWS Lambda Proxy Event/Response', () =
251251
expect(event.requestContext.http.userAgent).toBe('daniel-api')
252252
expect(event.headers['User-Agent']).toBe('daniel-api')
253253
})
254+
255+
it('converts axios call with array query params containing strings, undefined, and numbers', () => {
256+
// given
257+
const axiosConfig: AxiosRequestConfig = {
258+
method: 'get',
259+
url: '/v1/items',
260+
params: {
261+
tags: ['foo', undefined, 'bar'],
262+
ids: [1, 2, undefined, 3],
263+
empty: [],
264+
mixed: ['a', 2, undefined, 'b'],
265+
}
266+
}
267+
const operation: Operation = {
268+
path: '/v1/items',
269+
method: HttpMethod.Get,
270+
responses: {}
271+
}
272+
273+
// then
274+
const event = convertAxiosToApiGw(axiosConfig, operation)
275+
expect(event.queryStringParameters).toEqual({
276+
tags: 'foo,bar',
277+
ids: '1,2,3',
278+
empty: '',
279+
mixed: 'a,2,b'
280+
})
281+
expect(event.rawQueryString).toEqual('tags=foo&tags=bar&ids=1&ids=2&ids=3&empty=&mixed=a&mixed=2&mixed=b')
282+
})
283+
254284
})
255285

256286
describe('Api GW Proxy Response to Axios Response', () => {

src/openapi-lambda-adapters.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import type {
2-
APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2,
3-
APIGatewayProxyEventQueryStringParameters, APIGatewayProxyEventPathParameters,
2+
APIGatewayProxyEventPathParameters,
3+
APIGatewayProxyEventQueryStringParameters,
44
APIGatewayProxyEventV2WithLambdaAuthorizer,
5+
APIGatewayProxyStructuredResultV2,
56
Context
67
} from 'aws-lambda'
78

89
import createDebug from 'debug'
910

1011
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
11-
import type { Runner, Operation, UnknownContext } from 'openapi-client-axios'
12-
import { invokeLambda } from './lambda-invoker'
1312
import { params } from 'bath/params'
14-
import { safeParseJson } from './util'
13+
import type { Operation, Runner, UnknownContext } from 'openapi-client-axios'
1514
import { v4 as uuidv4 } from 'uuid'
15+
import { invokeLambda } from './lambda-invoker'
16+
import { safeParseJson } from './util'
1617

1718
const debug = createDebug('openapi-lambda-adapter')
1819

@@ -43,17 +44,26 @@ export const convertAxiosToApiGw = (config: AxiosRequestConfig, operation: Opera
4344
...parsedParams
4445
}
4546

46-
// extract query params -> convert each value to ta string
47+
// extract query params -> convert each value to a string
4748
const queryParams = Object.entries(config.params ?? {}).filter(entryValueExists).reduce<APIGatewayProxyEventQueryStringParameters>((queryParams, [key, val]) => {
48-
queryParams[key] = val?.toString()
49+
if (Array.isArray(val)) {
50+
// Use valueExists to filter out undefined/null
51+
queryParams[key] = val.filter(valueExists).map(v => v.toString()).join(',')
52+
} else {
53+
queryParams[key] = val?.toString()
54+
}
4955
return queryParams
5056
}, {})
5157

5258
const queryString: string[] = []
5359
Object.entries(config.params ?? {}).filter(entryValueExists).forEach(([key, val]) => {
54-
if (val && Array.isArray(val)) {
60+
if (Array.isArray(val)) {
61+
const filtered = val.filter(valueExists)
5562
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
56-
queryString.push(...val.map((entry) => `${key}=${entry.toString()}`))
63+
queryString.push(...filtered.map((entry) => `${key}=${entry.toString()}`))
64+
if (filtered.length === 0) {
65+
queryString.push(`${key}=`)
66+
}
5767
} else {
5868
queryString.push(`${key}=${val.toString()}`)
5969
}
@@ -134,7 +144,9 @@ export const convertApiGwToAxios = (resp: APIGatewayProxyStructuredResultV2, axi
134144
return axiosResp
135145
}
136146

137-
const entryValueExists = (entry: [string, unknown]): boolean => entry[1] !== null && entry[1] !== undefined
147+
const entryValueExists = (entry: [string, unknown]): boolean => valueExists(entry[1])
148+
149+
const valueExists = (value: unknown): boolean => value !== null && value !== undefined
138150

139151
class AxiosError extends Error {
140152
public readonly code: string

0 commit comments

Comments
 (0)