-
-
Notifications
You must be signed in to change notification settings - Fork 435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(adapter): handle multi value headers in AWS Lambda #2494
Changes from 7 commits
b36d9c0
0e5ec2c
0ec2c09
485d98c
57967de
72336fd
389da2c
d51f022
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ export interface APIGatewayProxyEventV2 { | |
version: string | ||
routeKey: string | ||
headers: Record<string, string | undefined> | ||
multiValueHeaders?: undefined | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is your rationale for this? The documentation does not appear to include multiValueHeaders in ver 2.0. https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It simplifies code in my opinion. It allows event.multiValueHeaders?.['host']?.[0] instead of 'multiValueHeaders' in event
? event.multiValueHeaders.['host']?.[0]
: undefined and it also allows } else if (event.multiValueHeaders) {
for (const [k, values] of
Object.entries(event.multiValueHeaders)) { instead of } else if ('multiValueHeaders' in event) {
for (const [k, values] of
Object.entries(event.multiValueHeaders || {})) { There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you. The implementation is clean, and I think this is good. Note. Below is a note for when the need arises to completely remove 'multiValueHeaders'. const createRequest = (event: LambdaEvent) => {
const queryString = extractQueryString(event)
const domainName =
event.requestContext && 'domainName' in event.requestContext
? event.requestContext.domainName
: getHostFromEvent(event)
const path = isProxyEventV2(event) ? event.rawPath : event.path
const urlPath = `https://${domainName}${path}`
const url = queryString ? `${urlPath}?${queryString}` : urlPath
const headers = new Headers()
getCookies(event, headers)
if (event.headers) {
for (const [k, v] of Object.entries(event.headers)) {
if (v) {
headers.set(k, v)
}
}
}
if (isAPIGatewayProxyEvent(event) && event.multiValueHeaders) {
for (const [k, values] of Object.entries(event.multiValueHeaders)) {
if (values) {
values.forEach((v) => headers.append(k, v))
}
}
}
const method = isProxyEventV2(event) ? event.requestContext.http.method : event.httpMethod
const requestInit: RequestInit = {
headers,
method,
}
if (event.body) {
requestInit.body = event.isBase64Encoded ? Buffer.from(event.body, 'base64') : event.body
}
return new Request(url, requestInit)
}
const getHostFromEvent = (event: LambdaEvent): string => {
if (!event.headers) {
return 'localhost'
}
if (isAPIGatewayProxyEvent(event)) {
return event.headers['host'] ?? event.multiValueHeaders?.['host']?.[0] ?? 'localhost'
} else {
return event.headers['host'] ?? 'localhost'
}
} const isAPIGatewayProxyEvent = (event: LambdaEvent): event is APIGatewayProxyEvent => {
return 'multiValueHeaders' in event
} |
||
cookies?: string[] | ||
rawPath: string | ||
rawQueryString: string | ||
|
@@ -63,7 +64,8 @@ export interface APIGatewayProxyEvent { | |
// When calling Lambda through an Application Load Balancer | ||
export interface ALBProxyEvent { | ||
httpMethod: string | ||
headers: Record<string, string | undefined> | ||
headers?: Record<string, string | undefined> | ||
multiValueHeaders?: Record<string, string[] | undefined> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
path: string | ||
body: string | null | ||
isBase64Encoded: boolean | ||
|
@@ -198,16 +200,24 @@ const createRequest = (event: LambdaEvent) => { | |
const domainName = | ||
event.requestContext && 'domainName' in event.requestContext | ||
? event.requestContext.domainName | ||
: event.headers['host'] | ||
: event.headers?.['host'] ?? event.multiValueHeaders?.['host']?.[0] | ||
const path = isProxyEventV2(event) ? event.rawPath : event.path | ||
const urlPath = `https://${domainName}${path}` | ||
const url = queryString ? `${urlPath}?${queryString}` : urlPath | ||
|
||
const headers = new Headers() | ||
getCookies(event, headers) | ||
for (const [k, v] of Object.entries(event.headers)) { | ||
if (v) { | ||
headers.set(k, v) | ||
if (event.headers) { | ||
for (const [k, v] of Object.entries(event.headers)) { | ||
if (v) { | ||
headers.set(k, v) | ||
} | ||
} | ||
} else if (event.multiValueHeaders) { | ||
for (const [k, values] of Object.entries(event.multiValueHeaders)) { | ||
if (values) { | ||
values.forEach((v) => headers.append(k, v)) | ||
} | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is complicated, but it seems better to maintain
runtime_tests/lambda
instead of here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to d51f022
And added tests for APIGW V1 and V2 as well.