Skip to content

Commit

Permalink
refactor: change all functions to object params
Browse files Browse the repository at this point in the history
  • Loading branch information
brettstack committed Apr 29, 2019
1 parent 27fde25 commit 149b14a
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 51 deletions.
28 changes: 14 additions & 14 deletions __tests__/unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ test('getPathWithQueryStringParams: no params', () => {
const event = {
path: '/foo/bar'
}
const pathWithQueryStringParams = awsServerlessExpress.getPathWithQueryStringParams(event)
const pathWithQueryStringParams = awsServerlessExpress.getPathWithQueryStringParams({ event })
expect(pathWithQueryStringParams).toEqual('/foo/bar')
})

Expand All @@ -18,7 +18,7 @@ test('getPathWithQueryStringParams: 1 param', () => {
'bizz': 'bazz'
}
}
const pathWithQueryStringParams = awsServerlessExpress.getPathWithQueryStringParams(event)
const pathWithQueryStringParams = awsServerlessExpress.getPathWithQueryStringParams({ event })
expect(pathWithQueryStringParams).toEqual('/foo/bar?bizz=bazz')
})

Expand All @@ -29,7 +29,7 @@ test('getPathWithQueryStringParams: to be url-encoded param', () => {
'redirect_uri': 'http://lvh.me:3000/cb'
}
}
const pathWithQueryStringParams = awsServerlessExpress.getPathWithQueryStringParams(event)
const pathWithQueryStringParams = awsServerlessExpress.getPathWithQueryStringParams({ event })
expect(pathWithQueryStringParams).toEqual('/foo/bar?redirect_uri=http%3A%2F%2Flvh.me%3A3000%2Fcb')
})

Expand All @@ -41,7 +41,7 @@ test('getPathWithQueryStringParams: 2 params', () => {
'buzz': 'bozz'
}
}
const pathWithQueryStringParams = awsServerlessExpress.getPathWithQueryStringParams(event)
const pathWithQueryStringParams = awsServerlessExpress.getPathWithQueryStringParams({ event })
expect(pathWithQueryStringParams).toEqual('/foo/bar?bizz=bazz&buzz=bozz')
})

Expand All @@ -58,7 +58,7 @@ function mapApiGatewayEventToHttpRequest (headers) {
'foo': 'bar'
}
const socketPath = '/tmp/server0.sock'
const httpRequest = awsServerlessExpress.mapApiGatewayEventToHttpRequest(event, context, socketPath)
const httpRequest = awsServerlessExpress.mapApiGatewayEventToHttpRequest({ event, context, socketPath })

return {httpRequest, eventClone, context}
}
Expand Down Expand Up @@ -95,7 +95,7 @@ test('mapApiGatewayEventToHttpRequest: without headers', () => {
})

test('getSocketPath', () => {
const socketPath = awsServerlessExpress.getSocketPath('12345abcdef')
const socketPath = awsServerlessExpress.getSocketPath({ socketPathSuffix: '12345abcdef' })
const isWin = process.platform === 'win32'
const expectedSocketPath = isWin ? path.join('\\\\?\\\\pipe\\\\', process.cwd(), 'server-12345abcdef') : '/tmp/server-12345abcdef.sock'
expect(socketPath).toBe(expectedSocketPath)
Expand Down Expand Up @@ -136,7 +136,7 @@ describe('forwardConnectionErrorResponseToApiGateway', () => {
const contextResolver = {
succeed: (p) => context.succeed(p.response)
}
awsServerlessExpress.forwardConnectionErrorResponseToApiGateway('ERROR', contextResolver)
awsServerlessExpress.forwardConnectionErrorResponseToApiGateway({ error: 'ERROR', resolver: contextResolver })
}
).then(successResponse => expect(successResponse).toEqual({
statusCode: 502,
Expand All @@ -154,7 +154,7 @@ describe('forwardLibraryErrorResponseToApiGateway', () => {
const contextResolver = {
succeed: (p) => context.succeed(p.response)
}
awsServerlessExpress.forwardLibraryErrorResponseToApiGateway('ERROR', contextResolver)
awsServerlessExpress.forwardLibraryErrorResponseToApiGateway({ error: 'ERROR', resolver: contextResolver })
}
).then(successResponse => expect(successResponse).toEqual({
statusCode: 500,
Expand Down Expand Up @@ -184,7 +184,7 @@ describe('forwardResponseToApiGateway: header handling', () => {
return new Promise(
(resolve, reject) => {
const contextResolver = getContextResolver(resolve)
awsServerlessExpress.forwardResponseToApiGateway(server, response, contextResolver)
awsServerlessExpress.forwardResponseToApiGateway({ server, response, resolver: contextResolver })
}
).then(successResponse => expect(successResponse).toEqual({
statusCode: 200,
Expand All @@ -208,7 +208,7 @@ describe('forwardResponseToApiGateway: content-type encoding', () => {
return new Promise(
(resolve, reject) => {
const contextResolver = getContextResolver(resolve)
awsServerlessExpress.forwardResponseToApiGateway(server, response, contextResolver)
awsServerlessExpress.forwardResponseToApiGateway({ server, response, resolver: contextResolver })
}
).then(successResponse => expect(successResponse).toEqual({
statusCode: 200,
Expand All @@ -226,7 +226,7 @@ describe('forwardResponseToApiGateway: content-type encoding', () => {
return new Promise(
(resolve, reject) => {
const contextResolver = getContextResolver(resolve)
awsServerlessExpress.forwardResponseToApiGateway(server, response, contextResolver)
awsServerlessExpress.forwardResponseToApiGateway({ server, response, resolver: contextResolver })
}
).then(successResponse => expect(successResponse).toEqual({
statusCode: 200,
Expand All @@ -244,7 +244,7 @@ describe('forwardResponseToApiGateway: content-type encoding', () => {
return new Promise(
(resolve, reject) => {
const contextResolver = getContextResolver(resolve)
awsServerlessExpress.forwardResponseToApiGateway(server, response, contextResolver)
awsServerlessExpress.forwardResponseToApiGateway({ server, response, resolver: contextResolver })
}
).then(successResponse => expect(successResponse).toEqual({
statusCode: 200,
Expand All @@ -262,7 +262,7 @@ describe('forwardResponseToApiGateway: content-type encoding', () => {
return new Promise(
(resolve, reject) => {
const contextResolver = getContextResolver(resolve)
awsServerlessExpress.forwardResponseToApiGateway(server, response, contextResolver)
awsServerlessExpress.forwardResponseToApiGateway({ server, response, resolver: contextResolver })
}
).then(successResponse => expect(successResponse).toEqual({
statusCode: 200,
Expand All @@ -280,7 +280,7 @@ describe('forwardResponseToApiGateway: content-type encoding', () => {
return new Promise(
(resolve, reject) => {
const contextResolver = getContextResolver(resolve)
awsServerlessExpress.forwardResponseToApiGateway(server, response, contextResolver)
awsServerlessExpress.forwardResponseToApiGateway({ server, response, resolver: contextResolver })
}
).then(successResponse => expect(successResponse).toEqual({
statusCode: 200,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"prerelease": true
},
{
"name": "next",
"name": "v4",
"channel": "alpha",
"prerelease": true
}
Expand Down
87 changes: 56 additions & 31 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,48 +18,48 @@ const url = require('url')
const binarycase = require('binary-case')
const isType = require('type-is')

function getPathWithQueryStringParams (event) {
function getPathWithQueryStringParams ({ event }) {
return url.format({
pathname: event.path,
query: event.queryStringParameters
})
}

function getEventBody (event) {
function getEventBody ({ event }) {
return Buffer.from(event.body, event.isBase64Encoded ? 'base64' : 'utf8')
}

function clone (json) {
return JSON.parse(JSON.stringify(json))
function clone ({ object }) {
return JSON.parse(JSON.stringify(object))
}

function getContentType (params) {
function getContentType ({ contentTypeHeader }) {
// only compare mime type; ignore encoding part
return params.contentTypeHeader ? params.contentTypeHeader.split(';')[0] : ''
return contentTypeHeader ? contentTypeHeader.split(';')[0] : ''
}

function isContentTypeBinaryMimeType (params) {
return params.binaryMimeTypes.length > 0 && !!isType.is(params.contentType, params.binaryMimeTypes)
function isContentTypeBinaryMimeType ({ contentType, binaryMimeTypes }) {
return binaryMimeTypes.length > 0 && !!isType.is(contentType, binaryMimeTypes)
}

function mapApiGatewayEventToHttpRequest (event, context, socketPath) {
function mapApiGatewayEventToHttpRequest ({ event, context, socketPath }) {
const headers = Object.assign({}, event.headers)

// NOTE: API Gateway is not setting Content-Length header on requests even when they have a body
if (event.body && !headers['Content-Length']) {
const body = getEventBody(event)
const body = getEventBody({ event })
headers['Content-Length'] = Buffer.byteLength(body)
}

const clonedEventWithoutBody = clone(event)
const clonedEventWithoutBody = clone({ object: event })
delete clonedEventWithoutBody.body

headers['x-apigateway-event'] = encodeURIComponent(JSON.stringify(clonedEventWithoutBody))
headers['x-apigateway-context'] = encodeURIComponent(JSON.stringify(context))

return {
method: event.httpMethod,
path: getPathWithQueryStringParams(event),
path: getPathWithQueryStringParams({ event }),
headers,
socketPath
// protocol: `${headers['X-Forwarded-Proto']}:`,
Expand All @@ -69,7 +69,7 @@ function mapApiGatewayEventToHttpRequest (event, context, socketPath) {
}
}

function forwardResponseToApiGateway (server, response, resolver) {
function forwardResponseToApiGateway ({ server, response, resolver }) {
let buf = []

response
Expand Down Expand Up @@ -122,7 +122,7 @@ function forwardResponseToApiGateway (server, response, resolver) {
})
}

function forwardConnectionErrorResponseToApiGateway (error, resolver) {
function forwardConnectionErrorResponseToApiGateway ({ error, resolver }) {
console.log('ERROR: aws-serverless-express connection error')
console.error(error)
const errorResponse = {
Expand All @@ -136,7 +136,7 @@ function forwardConnectionErrorResponseToApiGateway (error, resolver) {
})
}

function forwardLibraryErrorResponseToApiGateway (error, resolver) {
function forwardLibraryErrorResponseToApiGateway ({ error, resolver }) {
console.log('ERROR: aws-serverless-express error')
console.error(error)
const errorResponse = {
Expand All @@ -150,30 +150,38 @@ function forwardLibraryErrorResponseToApiGateway (error, resolver) {
})
}

function forwardRequestToNodeServer (server, event, context, resolver) {
function forwardRequestToNodeServer ({
server,
event,
context,
resolver
}) {
try {
const requestOptions = mapApiGatewayEventToHttpRequest(event, context, getSocketPath(server._socketPathSuffix))
const req = http.request(requestOptions, (response) => forwardResponseToApiGateway(server, response, resolver))
const requestOptions = mapApiGatewayEventToHttpRequest({
event,
context,
socketPath: getSocketPath({ socketPathSuffix: server._socketPathSuffix })
})
const req = http.request(requestOptions, (response) => forwardResponseToApiGateway({ server, response, resolver }))

if (event.body) {
const body = getEventBody(event)

const body = getEventBody({ event })
req.write(body)
}

req.on('error', (error) => forwardConnectionErrorResponseToApiGateway(error, resolver))
req.on('error', (error) => forwardConnectionErrorResponseToApiGateway({ error, resolver }))
.end()
} catch (error) {
forwardLibraryErrorResponseToApiGateway(error, resolver)
forwardLibraryErrorResponseToApiGateway({ error, resolver })
return server
}
}

function startServer (server) {
return server.listen(getSocketPath(server._socketPathSuffix))
function startServer ({ server }) {
return server.listen(getSocketPath({ socketPathSuffix: server._socketPathSuffix }))
}

function getSocketPath (socketPathSuffix) {
function getSocketPath ({ socketPathSuffix }) {
/* only running tests on Linux; Window support is for local dev only */
/* istanbul ignore if */
if (/^win/.test(process.platform)) {
Expand All @@ -199,9 +207,9 @@ function createServer ({
server.on('error', (error) => {
/* istanbul ignore else */
if (error.code === 'EADDRINUSE') {
console.warn(`WARNING: Attempting to listen on socket ${getSocketPath(server._socketPathSuffix)}, but it is already in use. This is likely as a result of a previous invocation error or timeout. Check the logs for the invocation(s) immediately prior to this for root cause, and consider increasing the timeout and/or cpu/memory allocation if this is purely as a result of a timeout. aws-serverless-express will restart the Node.js server listening on a new port and continue with this request.`)
console.warn(`WARNING: Attempting to listen on socket ${getSocketPath({ socketPathSuffix: server._socketPathSuffix })}, but it is already in use. This is likely as a result of a previous invocation error or timeout. Check the logs for the invocation(s) immediately prior to this for root cause, and consider increasing the timeout and/or cpu/memory allocation if this is purely as a result of a timeout. aws-serverless-express will restart the Node.js server listening on a new port and continue with this request.`)
server._socketPathSuffix = getRandomString()
return server.close(() => startServer(server))
return server.close(() => startServer({ server }))
} else {
console.log('ERROR: aws-serverless-express server error')
console.error(error)
Expand All @@ -211,12 +219,19 @@ function createServer ({
return server
}

function getEventSourceBasedOnEvent ({
eventSource
}) {
return 'API_GATEWAY'
}

function proxy ({
server,
event = {},
context = {},
callback = null,
resolutionMode = 'CONTEXT_SUCCEED'
resolutionMode = 'CONTEXT_SUCCEED',
eventSource = getEventSourceBasedOnEvent({ event })
}) {
return {
server,
Expand All @@ -233,10 +248,20 @@ function proxy ({
})

if (server.listening) {
forwardRequestToNodeServer(server, event, context, resolver)
forwardRequestToNodeServer({
server,
event,
context,
resolver
})
} else {
startServer(server)
.on('listening', () => forwardRequestToNodeServer(server, event, context, resolver))
startServer({ server })
.on('listening', () => forwardRequestToNodeServer({
server,
event,
context,
resolver
}))
}
})
}
Expand Down
9 changes: 4 additions & 5 deletions src/middleware.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
module.exports.eventContext = options => function apiGatewayEventParser (req, res, next) {
options = options || {} // defaults: {reqPropKey: 'apiGateway', deleteHeaders: true}
const reqPropKey = options.reqPropKey || 'apiGateway'
const deleteHeaders = options.deleteHeaders === undefined ? true : options.deleteHeaders

module.exports.eventContext = ({
reqPropKey = 'apiGateway',
deleteHeaders = true
} = {}) => function apiGatewayEventParser (req, res, next) {
if (!req.headers['x-apigateway-event'] || !req.headers['x-apigateway-context']) {
console.error('Missing x-apigateway-event or x-apigateway-context header(s)')
next()
Expand Down

0 comments on commit 149b14a

Please sign in to comment.