Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ $ npm i @fastify/aws-lambda
| property | description | default value |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ------------- |
| binaryMimeTypes | Array of binary MimeTypes to handle | `[]` |
| enforceBase64 | Function that receives the reply and returns a boolean indicating if the response content is binary or not | `undefined` |
| serializeLambdaArguments | Activate the serialization of lambda Event and Context in http header `x-apigateway-event` `x-apigateway-context` | `false` *(was `true` for <v2.0.0)* |
| decorateRequest | Decorates the fastify request with the lambda Event and Context `request.awsLambda.event` `request.awsLambda.context` | `true` |
| decorationPropertyName | The default property name for request decoration | `awsLambda` |
Expand Down
3 changes: 2 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Context } from "aws-lambda";
import { FastifyInstance } from "fastify";
import { FastifyInstance, FastifyReply } from "fastify";

export interface LambdaFastifyOptions {
binaryMimeTypes?: string[];
callbackWaitsForEmptyEventLoop?: boolean;
serializeLambdaArguments?: boolean;
decorateRequest?: boolean;
decorationPropertyName?: string;
enforceBase64?: (reply: FastifyReply) => boolean;
}

export interface LambdaResponse {
Expand Down
10 changes: 9 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
const isCompressed = (res) => {
const contentEncoding = res.headers['content-encoding'] || res.headers['Content-Encoding']
return contentEncoding && contentEncoding !== 'identity'
}

const customBinaryCheck = (options, res) =>
typeof options.enforceBase64 === 'function' && options.enforceBase64(res) === true

module.exports = (app, options) => {
options = options || {}
options.binaryMimeTypes = options.binaryMimeTypes || []
Expand Down Expand Up @@ -110,7 +118,7 @@ module.exports = (app, options) => {
})

const contentType = (res.headers['content-type'] || res.headers['Content-Type'] || '').split(';')[0]
const isBase64Encoded = options.binaryMimeTypes.indexOf(contentType) > -1
const isBase64Encoded = options.binaryMimeTypes.indexOf(contentType) > -1 || isCompressed(res) || customBinaryCheck(options, res)

const ret = {
statusCode: res.statusCode,
Expand Down
8 changes: 8 additions & 0 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ expectAssignable<LambdaFastifyOptions>({
decorateRequest: true,
decorationPropertyName: "myAWSstuff",
});
expectAssignable<LambdaFastifyOptions>({
binaryMimeTypes: ["foo", "bar"],
callbackWaitsForEmptyEventLoop: true,
serializeLambdaArguments: false,
decorateRequest: true,
decorationPropertyName: "myAWSstuff",
enforceBase64: (reply) => false,
});

expectError(awsLambdaFastify());
expectError(awsLambdaFastify(app, { neh: "definition" }));
80 changes: 80 additions & 0 deletions test/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,86 @@ test('GET with base64 encoding response', async (t) => {
t.equal(ret.headers['set-cookie'], 'qwerty=one')
})

test('GET with content-encoding response', async (t) => {
t.plan(16)

const readFileAsync = promisify(fs.readFile)
const fileBuffer = await readFileAsync(__filename)
const app = fastify()
app.get('/test', async (request, reply) => {
t.equal(request.headers['x-my-header'], 'wuuusaaa')
t.equal(request.headers['x-apigateway-event'], '%7B%22httpMethod%22%3A%22GET%22%2C%22path%22%3A%22%2Ftest%22%2C%22headers%22%3A%7B%22X-My-Header%22%3A%22wuuusaaa%22%2C%22Content-Type%22%3A%22application%2Fjson%22%7D%7D')
t.equal(request.headers['user-agent'], 'lightMyRequest')
t.equal(request.headers.host, 'localhost:80')
t.equal(request.headers['content-length'], '0')
reply.header('Set-Cookie', 'qwerty=one')
reply.header('content-encoding', 'br')
reply.send(fileBuffer)
})
const proxy = awsLambdaFastify(app, { binaryMimeTypes: [], serializeLambdaArguments: true })
const ret = await proxy({
httpMethod: 'GET',
path: '/test',
headers: {
'X-My-Header': 'wuuusaaa',
'Content-Type': 'application/json'
}
})
t.equal(ret.statusCode, 200)
t.equal(ret.body, fileBuffer.toString('base64'))
t.equal(ret.isBase64Encoded, true)
t.ok(ret.headers)
t.equal(ret.headers['content-type'], 'application/octet-stream')
t.ok(ret.headers['content-length'])
t.ok(ret.headers.date)
t.equal(ret.headers.connection, 'keep-alive')
t.same(ret.multiValueHeaders, undefined)
t.equal(ret.headers['set-cookie'], 'qwerty=one')
t.equal(ret.headers['content-encoding'], 'br')
})

test('GET with custom binary check response', async (t) => {
t.plan(16)

const readFileAsync = promisify(fs.readFile)
const fileBuffer = await readFileAsync(__filename)
const app = fastify()
app.get('/test', async (request, reply) => {
t.equal(request.headers['x-my-header'], 'wuuusaaa')
t.equal(request.headers['x-apigateway-event'], '%7B%22httpMethod%22%3A%22GET%22%2C%22path%22%3A%22%2Ftest%22%2C%22headers%22%3A%7B%22X-My-Header%22%3A%22wuuusaaa%22%2C%22Content-Type%22%3A%22application%2Fjson%22%7D%7D')
t.equal(request.headers['user-agent'], 'lightMyRequest')
t.equal(request.headers.host, 'localhost:80')
t.equal(request.headers['content-length'], '0')
reply.header('Set-Cookie', 'qwerty=one')
reply.header('X-Base64-Encoded', '1')
reply.send(fileBuffer)
})
const proxy = awsLambdaFastify(app, {
binaryMimeTypes: [],
serializeLambdaArguments: true,
enforceBase64: (reply) => reply.headers['x-base64-encoded'] === '1'
})
const ret = await proxy({
httpMethod: 'GET',
path: '/test',
headers: {
'X-My-Header': 'wuuusaaa',
'Content-Type': 'application/json'
}
})
t.equal(ret.statusCode, 200)
t.equal(ret.body, fileBuffer.toString('base64'))
t.equal(ret.isBase64Encoded, true)
t.ok(ret.headers)
t.equal(ret.headers['content-type'], 'application/octet-stream')
t.ok(ret.headers['content-length'])
t.ok(ret.headers.date)
t.equal(ret.headers.connection, 'keep-alive')
t.same(ret.multiValueHeaders, undefined)
t.equal(ret.headers['set-cookie'], 'qwerty=one')
t.equal(ret.headers['x-base64-encoded'], '1')
})

test('GET with multi-value query params', async (t) => {
t.plan(2)

Expand Down