UNPKG

@codegenie/serverless-express

Version:

This library enables you to utilize AWS Lambda and Amazon API Gateway to respond to web and API requests using your existing Node.js application framework.

181 lines (158 loc) 5.46 kB
const url = require('url') function getPathWithQueryStringParams ({ event, query = event.multiValueQueryStringParameters, // NOTE: Use `event.pathParameters.proxy` if available ({proxy+}); fall back to `event.path` path = (event.pathParameters && event.pathParameters.proxy && `/${event.pathParameters.proxy}`) || event.path, // NOTE: Strip base path for custom domains stripBasePath = '', replaceRegex = new RegExp(`^${stripBasePath}`) }) { return url.format({ pathname: path.replace(replaceRegex, ''), query }) } function getEventBody ({ event, body = event.body, isBase64Encoded = event.isBase64Encoded }) { return Buffer.from(body, isBase64Encoded ? 'base64' : 'utf8') } function getRequestValuesFromEvent ({ event, method = event.httpMethod, path = getPathWithQueryStringParams({ event }) }) { let headers = {} if (event.multiValueHeaders) { headers = getCommaDelimitedHeaders({ headersMap: event.multiValueHeaders, lowerCaseKey: true }) } else if (event.headers) { headers = event.headers } let body if (event.body) { body = getEventBody({ event }) const { isBase64Encoded } = event headers['content-length'] = Buffer.byteLength(body, isBase64Encoded ? 'base64' : 'utf8') } const remoteAddress = (event && event.requestContext && event.requestContext.identity && event.requestContext.identity.sourceIp) || '' return { method, headers, body, remoteAddress, path } } function getMultiValueHeaders ({ headers }) { const multiValueHeaders = {} Object.entries(headers).forEach(([headerKey, headerValue]) => { const headerArray = Array.isArray(headerValue) ? headerValue.map(String) : [String(headerValue)] multiValueHeaders[headerKey.toLowerCase()] = headerArray }) return multiValueHeaders } function getEventSourceNameBasedOnEvent ({ event }) { if (event.requestContext && event.requestContext.elb) return 'AWS_ALB' if (event.headers?.['x-amzn-lattice-network']) { console.warn('Lattice event v1 is not supported. Please use Lattice event v2.') } if (event.requestContext && event.requestContext.serviceNetworkArn && event.requestContext.serviceArn) return 'AWS_VPC_LATTICE_V2' if (event.eventSource === 'SelfManagedKafka') return 'AWS_SELF_MANAGED_KAFKA' if (event.Records) { const eventSource = event.Records[0] ? event.Records[0].EventSource || event.Records[0].eventSource : undefined if (eventSource === 'aws:sns') { return 'AWS_SNS' } if (eventSource === 'aws:dynamodb') { return 'AWS_DYNAMODB' } if (eventSource === 'aws:sqs') { return 'AWS_SQS' } if (eventSource === 'aws:kinesis') { return 'AWS_KINESIS_DATA_STREAM' } if (eventSource === 'aws:s3') { return 'AWS_S3' } return 'AWS_LAMBDA_EDGE' } if (event.requestContext) { // NOTE: Lambda Function URL follows the same format as AWS_API_GATEWAY_V2 return event.version === '2.0' ? 'AWS_API_GATEWAY_V2' : 'AWS_API_GATEWAY_V1' } if (event.traceContext) { const functionsExtensionVersion = process.env.FUNCTIONS_EXTENSION_VERSION if (!functionsExtensionVersion) { console.warn('The environment variable \'FUNCTIONS_EXTENSION_VERSION\' is not set. Only the function runtime \'~3\' is supported.') } else if (functionsExtensionVersion === '~3') { return 'AZURE_HTTP_FUNCTION_V3' } else if (functionsExtensionVersion === '~4') { return 'AZURE_HTTP_FUNCTION_V4' } else { console.warn('The function runtime \'' + functionsExtensionVersion + '\' is not supported. Only \'~3\' and \'~4\' are supported.') } } if ( event.version && event.version === '0' && event.id && event['detail-type'] && event.source && event.account && event.time && event.region && event.resources && Array.isArray(event.resources) && event.detail && typeof event.detail === 'object' && !Array.isArray(event.detail) ) { // AWS doesn't have a defining Event Source here, so we're being incredibly selective on the structure // Ref: https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchevents.html return 'AWS_EVENTBRIDGE' } if (event.context && event.context.Execution && event.context.State && event.context.StateMachine) { return 'AWS_STEP_FUNCTIONS' } throw new Error('Unable to determine event source based on event.') } function getCommaDelimitedHeaders ({ headersMap, separator = ',', lowerCaseKey = false }) { const commaDelimitedHeaders = {} Object.entries(headersMap) .forEach(([headerKey, headerValue]) => { const newKey = lowerCaseKey ? headerKey.toLowerCase() : headerKey if (Array.isArray(headerValue)) { commaDelimitedHeaders[newKey] = headerValue.join(separator) } else { commaDelimitedHeaders[newKey] = headerValue } }) return commaDelimitedHeaders } const emptyResponseMapper = () => {} const parseCookie = (str) => str.split(';') .map((v) => v.split('=')) .reduce((acc, v) => { if (!v[1]) { return acc } acc[decodeURIComponent(v[0].trim().toLowerCase())] = decodeURIComponent(v[1].trim()) return acc }, {}) module.exports = { getPathWithQueryStringParams, getRequestValuesFromEvent, getMultiValueHeaders, getEventSourceNameBasedOnEvent, getEventBody, getCommaDelimitedHeaders, emptyResponseMapper, parseCookie }