diff --git a/src/adapters/aws/api-gateway-v1.adapter.ts b/src/adapters/aws/api-gateway-v1.adapter.ts index f0175511..1724aeea 100644 --- a/src/adapters/aws/api-gateway-v1.adapter.ts +++ b/src/adapters/aws/api-gateway-v1.adapter.ts @@ -8,6 +8,7 @@ import type { GetResponseAdapterProps, OnErrorProps, } from '../../contracts'; +import { keysToLowercase } from '../../core'; import { type StripBasePathFn, buildStripBasePath, @@ -42,6 +43,13 @@ export interface ApiGatewayV1Options { * @defaultValue true */ throwOnChunkedTransferEncoding?: boolean; + + /** + * Emulates the behavior of Node.js `http` module by ensuring all request headers are lowercase. + * + * @defaultValue false + */ + lowercaseRequestHeaders?: boolean; } /** @@ -122,7 +130,9 @@ export class ApiGatewayV1Adapter */ public getRequest(event: APIGatewayProxyEvent): AdapterRequest { const method = event.httpMethod; - const headers = { ...event.headers }; + const headers = this.options?.lowercaseRequestHeaders + ? keysToLowercase(event.headers) + : { ...event.headers }; for (const multiValueHeaderKey of Object.keys( event.multiValueHeaders || {}, diff --git a/src/core/headers.ts b/src/core/headers.ts index 1bb43bdc..28e15d8c 100644 --- a/src/core/headers.ts +++ b/src/core/headers.ts @@ -151,3 +151,12 @@ export function parseHeaders( return result; } + +export function keysToLowercase>( + obj: T, +): { [K in keyof T as Lowercase]: T[K] } { + const result: any = {}; + for (const [k, v] of Object.entries(obj)) result[k.toLowerCase()] = v; + + return result as { [K in keyof T as Lowercase]: T[K] }; +} diff --git a/test/adapters/aws/api-gateway-v1.adapter.spec.ts b/test/adapters/aws/api-gateway-v1.adapter.spec.ts index 75536483..6e29f3c2 100644 --- a/test/adapters/aws/api-gateway-v1.adapter.spec.ts +++ b/test/adapters/aws/api-gateway-v1.adapter.spec.ts @@ -75,6 +75,22 @@ describe(ApiGatewayV1Adapter.name, () => { expect(result).toHaveProperty('path', resultPath); }); + it('should return lowercase request headers if option `lowercaseRequestHeaders` is `true`', () => { + const method = 'GET'; + const path = '/events'; + + adapter = new ApiGatewayV1Adapter({ lowercaseRequestHeaders: true }); + const event = createApiGatewayV1(method, path); + event.headers['Cookie'] = 'test=test;'; + + const { headers } = adapter.getRequest(event); + + expect(headers).not.toHaveProperty('Cookie'); + expect(headers).toHaveProperty('cookie'); + expect(headers).not.toHaveProperty('Accept'); + expect(headers).toHaveProperty('accept'); + }); + it('should return the correct mapping for the request when it has no body', () => { const method = 'GET'; const path = '/users'; diff --git a/www/docs/main/adapters/aws/api-gateway-v1.mdx b/www/docs/main/adapters/aws/api-gateway-v1.mdx index 99ba18a5..0c37415c 100644 --- a/www/docs/main/adapters/aws/api-gateway-v1.mdx +++ b/www/docs/main/adapters/aws/api-gateway-v1.mdx @@ -119,6 +119,15 @@ When you configure your API with some `basePath` like `/prod`, you should either ::: +You can also ensure request headers are lowercase like the default behavior of Node.js `http` module by setting the `lowercaseRequestHeaders` option to `true`. + +:::caution + +ApiGateway may already be ensuring your headers are lowercase but it may be worth confirming in your own system as many libraries in the Node.js ecosystem will assume this lowercasing. + +::: + + ## Usage To add support to AWS API Gateway V1 you do the following: