diff --git a/lib/serverless/api-gateway.js b/lib/serverless/api-gateway.js index 14746441cb..8f053fd4d2 100644 --- a/lib/serverless/api-gateway.js +++ b/lib/serverless/api-gateway.js @@ -97,6 +97,10 @@ function normalizeHeaders(event, lowerCaseKey = false) { /** * Determines if Lambda event appears to be a valid Lambda Proxy event. + * There are multiple types of events possible. They are described at + * https://docs.aws.amazon.com/lambda/latest/dg/services-apigateway.html#services-apigateway-apitypes. + * Each type of event has its own event payload structure; some types have + * multiple versions of the payload structure. * * @param {object} event The event to inspect. * @returns {boolean} Whether the given object contains fields necessary @@ -106,7 +110,8 @@ function isLambdaProxyEvent(event) { return isGatewayV1Event(event) || isGatewayV2Event(event) } -const v1Keys = [ +// See https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format +const restApiV1Keys = [ 'body', 'headers', 'httpMethod', @@ -118,16 +123,23 @@ const v1Keys = [ 'queryStringParameters', 'requestContext', 'resource', - 'stageVariables', - 'version' + 'stageVariables' ].join(',') +// See https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html +const httpApiV1Keys = [...restApiV1Keys.split(','), 'version'].join(',') + function isGatewayV1Event(event) { const keys = Object.keys(event).sort().join(',') - return keys === v1Keys && event?.version === '1.0' + if (keys === httpApiV1Keys && event?.version === '1.0') { + return true + } + + return keys === restApiV1Keys } -const v2Keys = [ +// See https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html +const httpApiV2Keys = [ 'body', 'cookies', 'headers', @@ -144,7 +156,7 @@ const v2Keys = [ function isGatewayV2Event(event) { const keys = Object.keys(event).sort().join(',') - return keys === v2Keys && event?.version === '2.0' + return keys === httpApiV2Keys && event?.version === '2.0' } /** diff --git a/test/unit/serverless/fixtures.js b/test/unit/serverless/fixtures.js index 55fbaa81d7..87c30d43f7 100644 --- a/test/unit/serverless/fixtures.js +++ b/test/unit/serverless/fixtures.js @@ -5,8 +5,7 @@ 'use strict' -// https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html -const gatewayV1Event = { +const httpApiGatewayV1Event = { version: '1.0', resource: '/my/path', path: '/my/path', @@ -77,8 +76,79 @@ const gatewayV1Event = { isBase64Encoded: false } +// https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format +const restApiGatewayV1Event = { + resource: '/my/path', + path: '/my/path', + httpMethod: 'GET', + headers: { + header1: 'value1', + header2: 'value2' + }, + multiValueHeaders: { + header1: ['value1'], + header2: ['value1', 'value2'] + }, + queryStringParameters: { + parameter1: 'value1', + parameter2: 'value' + }, + multiValueQueryStringParameters: { + parameter1: ['value1', 'value2'], + parameter2: ['value'] + }, + requestContext: { + accountId: '123456789012', + apiId: 'id', + authorizer: { + claims: null, + scopes: null + }, + domainName: 'id.execute-api.us-east-1.amazonaws.com', + domainPrefix: 'id', + extendedRequestId: 'request-id', + httpMethod: 'GET', + identity: { + accessKey: null, + accountId: null, + caller: null, + cognitoAuthenticationProvider: null, + cognitoAuthenticationType: null, + cognitoIdentityId: null, + cognitoIdentityPoolId: null, + principalOrgId: null, + sourceIp: '192.0.2.1', + user: null, + userAgent: 'user-agent', + userArn: null, + clientCert: { + clientCertPem: 'CERT_CONTENT', + subjectDN: 'www.example.com', + issuerDN: 'Example issuer', + serialNumber: 'a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1', + validity: { + notBefore: 'May 28 12:30:02 2019 GMT', + notAfter: 'Aug 5 09:36:04 2021 GMT' + } + } + }, + path: '/my/path', + protocol: 'HTTP/1.1', + requestId: 'id=', + requestTime: '04/Mar/2020:19:15:17 +0000', + requestTimeEpoch: 1583349317135, + resourceId: null, + resourcePath: '/my/path', + stage: '$default' + }, + pathParameters: null, + stageVariables: null, + body: 'Hello from Lambda!', + isBase64Encoded: false +} + // https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html -const gatewayV2Event = { +const httpApiGatewayV2Event = { version: '2.0', routeKey: '$default', rawPath: '/my/path', @@ -175,7 +245,8 @@ const lambaV1InvocationEvent = { } module.exports = { - gatewayV1Event, - gatewayV2Event, + restApiGatewayV1Event, + httpApiGatewayV1Event, + httpApiGatewayV2Event, lambaV1InvocationEvent } diff --git a/test/unit/serverless/utils.test.js b/test/unit/serverless/utils.test.js index 40ba30fda2..a715310f8d 100644 --- a/test/unit/serverless/utils.test.js +++ b/test/unit/serverless/utils.test.js @@ -9,16 +9,23 @@ const test = require('node:test') const assert = require('node:assert') const { isGatewayV1Event, isGatewayV2Event } = require('../../../lib/serverless/api-gateway') -const { gatewayV1Event, gatewayV2Event, lambaV1InvocationEvent } = require('./fixtures') +const { + restApiGatewayV1Event, + httpApiGatewayV1Event, + httpApiGatewayV2Event, + lambaV1InvocationEvent +} = require('./fixtures') test('isGatewayV1Event', () => { - assert.equal(isGatewayV1Event(gatewayV1Event), true) - assert.equal(isGatewayV1Event(gatewayV2Event), false) + assert.equal(isGatewayV1Event(restApiGatewayV1Event), true) + assert.equal(isGatewayV1Event(httpApiGatewayV1Event), true) + assert.equal(isGatewayV1Event(httpApiGatewayV2Event), false) assert.equal(isGatewayV1Event(lambaV1InvocationEvent), false) }) test('isGatewayV2Event', () => { - assert.equal(isGatewayV2Event(gatewayV1Event), false) - assert.equal(isGatewayV2Event(gatewayV2Event), true) + assert.equal(isGatewayV2Event(restApiGatewayV1Event), false) + assert.equal(isGatewayV2Event(httpApiGatewayV1Event), false) + assert.equal(isGatewayV2Event(httpApiGatewayV2Event), true) assert.equal(isGatewayV2Event(lambaV1InvocationEvent), false) })