diff --git a/README.md b/README.md index 3cafcf6..af2b092 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,10 @@ $ npm i @fastify/aws-lambda | decorationPropertyName | The default property name for request decoration | `awsLambda` | | callbackWaitsForEmptyEventLoop | See: [Official Documentation](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-context.html#nodejs-prog-model-context-properties) | `undefined` | | retainStage | Retain the stage part of the API Gateway URL | `false` | -| pathParameterUsedAsPath | Use a defined pathParameter as path (i.e. `'proxy'`) | `false` | -| parseCommaSeparatedQueryParams | Parse querystring with commas into an array of values. Affects the behavior of the querystring parser with commas while using [Payload Format Version 2.0](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format) | `true` | -| payloadAsStream | If set to true the response is a stream and can be used with `awslambda.streamifyResponse` | `false` | +| pathParameterUsedAsPath | Use a defined pathParameter as path (i.e. `'proxy'`) | `false` | +| parseCommaSeparatedQueryParams | Parse querystring with commas into an array of values. Affects the behavior of the querystring parser with commas while using [Payload Format Version 2.0](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format) | `true` | +| payloadAsStream | If set to true the response is a stream and can be used with `awslambda.streamifyResponse` | `false` | +| albMultiValueHeaders | Set to true if using ALB with multi value headers attribute | `false` | ## 📖Example ### lambda.js diff --git a/index.js b/index.js index 7e7b4c6..35bc0ff 100644 --- a/index.js +++ b/index.js @@ -19,6 +19,7 @@ module.exports = (app, options) => { options.pathParameterUsedAsPath = options.pathParameterUsedAsPath !== undefined ? options.pathParameterUsedAsPath : false options.parseCommaSeparatedQueryParams = options.parseCommaSeparatedQueryParams !== undefined ? options.parseCommaSeparatedQueryParams : true options.payloadAsStream = options.payloadAsStream !== undefined ? options.payloadAsStream : false + options.albMultiValueHeaders = options.albMultiValueHeaders !== undefined ? options.albMultiValueHeaders : false let currentAwsArguments = {} if (options.decorateRequest) { options.decorationPropertyName = options.decorationPropertyName || 'awsLambda' @@ -80,6 +81,8 @@ module.exports = (app, options) => { Object.keys(event.multiValueHeaders).forEach((h) => { if (event.multiValueHeaders[h].length > 1) { headers[h] = event.multiValueHeaders[h] + } else if (event.multiValueHeaders[h].length === 1 && options.albMultiValueHeaders) { + headers[h] = event.multiValueHeaders[h][0] } }) } @@ -168,6 +171,12 @@ module.exports = (app, options) => { if (cookies && event.version === '2.0') ret.cookies = cookies if (multiValueHeaders && (!event.version || event.version === '1.0')) ret.multiValueHeaders = multiValueHeaders + if (options.albMultiValueHeaders) { + if (!ret.multiValueHeaders) ret.multiValueHeaders = {} + Object.entries(ret.headers).forEach(([key, value]) => { + ret.multiValueHeaders[key] = [value] + }) + } if (!options.payloadAsStream) { ret.body = isBase64Encoded ? res.rawPayload.toString('base64') : res.payload diff --git a/test/alb.test.js b/test/alb.test.js index bb6fd7b..479c222 100644 --- a/test/alb.test.js +++ b/test/alb.test.js @@ -214,4 +214,35 @@ describe('ALB Tests', async () => { assert.equal(ret.statusCode, 200) assert.equal(ret.body, '{"q$":["foo@bar","foo?bar"]}') }) + + it('GET with multi-value headers', async () => { + const app = fastify() + app.get('/test', async (request, reply) => { + assert.equal(request.headers['x-my-header'], 'wuuusaaa') + reply.send({ hello: 'world' }) + }) + const proxy = awsLambdaFastify(app, { + albMultiValueHeaders: true + }) + + const ret = await proxy({ + requestContext: { elb: { targetGroupArn: 'xxx' } }, + httpMethod: 'GET', + path: '/test', + multiValueHeaders: { + 'x-my-header': ['wuuusaaa'] + } + }) + assert.equal(ret.statusCode, 200) + assert.equal(ret.body, '{"hello":"world"}') + console.log(JSON.stringify(ret.multiValueHeaders)) + assert.ok(ret.multiValueHeaders) + assert.equal( + ret.headers['content-type'], + ['application/json; charset=utf-8'] + ) + assert.equal(ret.headers['content-length'], ['17']) + assert.ok(ret.headers.date) + assert.equal(ret.headers.connection, ['keep-alive']) + }) })