diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md index 79f7a7c0f..3f7022f99 100644 --- a/docs/providers/aws/events/apigateway.md +++ b/docs/providers/aws/events/apigateway.md @@ -332,10 +332,6 @@ Please note that those are the API keys names, not the actual values. Once you d Clients connecting to this Rest API will then need to set any of these API keys values in the `x-api-key` header of their request. This is only necessary for functions where the `private` property is set to true. -## Lambda Integration - -This method is more complicated and involves a lot more configuration of the `http` event syntax. - ### Request Parameters To pass optional and required parameters to your functions, so you can use them in API Gateway tests and SDK generation, marking them as `true` will make them required, `false` will make them optional. @@ -348,7 +344,6 @@ functions: - http: path: posts/create method: post - integration: lambda request: parameters: querystrings: @@ -369,13 +364,16 @@ functions: - http: path: posts/{id} method: get - integration: lambda request: parameters: paths: id: true ``` +## Lambda Integration + +This method is more complicated and involves a lot more configuration of the `http` event syntax. + ### Request templates #### Default Request Templates diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/validate.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/validate.js index 13ab37913..1d7e55b9d 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/validate.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/validate.js @@ -96,15 +96,42 @@ module.exports = { } } else if (http.integration === 'AWS_PROXY') { // show a warning when request / response config is used with AWS_PROXY (LAMBDA-PROXY) - if (http.request || http.response) { + if (http.request) { + const keys = Object.keys(http.request); + if (!(keys.length === 1 && keys[0] === 'parameters')) { + const requestWarningMessage = [ + 'Warning! You\'re using the LAMBDA-PROXY in combination with a request', + ` configuration in your function "${functionName}". Only the`, + ' \'request.parameters\' configs are available in conjunction with', + ' LAMBDA-PROXY. Serverless will remove this configuration automatically', + ' before deployment.', + ].join(''); + this.serverless.cli.log(requestWarningMessage); + for (const key of keys) { + if (key !== 'parameters') { + delete http.request[key]; + } + } + } + if (Object.keys(http.request).length === 0) { + // No keys left, delete the request object + delete http.request; + } else { + http.request = this.getRequest(http); + + if (http.request.parameters) { + http.request.parameters = this.getRequestParameters(http.request); + } + } + } + if (http.response) { const warningMessage = [ - 'Warning! You\'re using the LAMBDA-PROXY in combination with request / response', + 'Warning! You\'re using the LAMBDA-PROXY in combination with response', ` configuration in your function "${functionName}".`, ' Serverless will remove this configuration automatically before deployment.', ].join(''); this.serverless.cli.log(warningMessage); - delete http.request; delete http.response; } } else if (http.integration === 'HTTP' || http.integration === 'HTTP_PROXY') { @@ -246,7 +273,7 @@ module.exports = { const integration = this.getIntegration(http); if (integration === 'AWS_PROXY' - && typeof arn === 'string' && arn.match(/^arn:aws:cognito-idp/) && authorizer.claims) { + && typeof arn === 'string' && arn.match(/^arn:aws:cognito-idp/) && authorizer.claims) { const errorMessage = [ 'Cognito claims can only be filtered when using the lambda integration type', ]; diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/validate.test.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/validate.test.js index 6206c757b..6e9c6a12b 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/validate.test.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/validate.test.js @@ -945,7 +945,7 @@ describe('#validate()', () => { expect(() => awsCompileApigEvents.validate()).to.throw(Error); }); - it('should process request parameters', () => { + it('should process request parameters for lambda integration', () => { awsCompileApigEvents.serverless.service.functions = { first: { events: [ @@ -988,6 +988,49 @@ describe('#validate()', () => { }); }); + it('should process request parameters for lambda-proxy integration', () => { + awsCompileApigEvents.serverless.service.functions = { + first: { + events: [ + { + http: { + integration: 'lambda-proxy', + path: 'foo/bar', + method: 'GET', + request: { + parameters: { + querystrings: { + foo: true, + bar: false, + }, + paths: { + foo: true, + bar: false, + }, + headers: { + foo: true, + bar: false, + }, + }, + }, + }, + }, + ], + }, + }; + + const validated = awsCompileApigEvents.validate(); + expect(validated.events).to.be.an('Array').with.length(1); + expect(validated.events[0].http.request.parameters).to.deep.equal({ + 'method.request.querystring.foo': true, + 'method.request.querystring.bar': false, + 'method.request.path.foo': true, + 'method.request.path.bar': false, + 'method.request.header.foo': true, + 'method.request.header.bar': false, + }); + }); + it('should throw an error if the provided response config is not an object', () => { awsCompileApigEvents.serverless.service.functions = { first: { @@ -1262,11 +1305,51 @@ describe('#validate()', () => { awsCompileApigEvents.validate(); - expect(logStub.calledOnce).to.be.equal(true); + expect(logStub.calledTwice).to.be.equal(true); expect(logStub.args[0][0].length).to.be.at.least(1); }); - it('should remove request/response config with LAMBDA-PROXY', () => { + it('should not show a warning message when using request.parameter with LAMBDA-PROXY', () => { + awsCompileApigEvents.serverless.service.functions = { + first: { + events: [ + { + http: { + method: 'GET', + path: 'users/list', + integration: 'lambda-proxy', + request: { + parameters: { + querystrings: { + foo: true, + bar: false, + }, + paths: { + foo: true, + bar: false, + }, + headers: { + foo: true, + bar: false, + }, + }, + }, + }, + }, + ], + }, + }; + // initialize so we get the log method from the CLI in place + serverless.init(); + + const logStub = sinon.stub(serverless.cli, 'log'); + + awsCompileApigEvents.validate(); + + expect(logStub.called).to.be.equal(false); + }); + + it('should remove non-parameter request/response config with LAMBDA-PROXY', () => { awsCompileApigEvents.serverless.service.functions = { first: { events: [ @@ -1279,6 +1362,11 @@ describe('#validate()', () => { template: { 'template/1': '{ "stage" : "$context.stage" }', }, + parameters: { + paths: { + foo: true, + }, + }, }, response: {}, }, @@ -1294,8 +1382,10 @@ describe('#validate()', () => { const validated = awsCompileApigEvents.validate(); expect(validated.events).to.be.an('Array').with.length(1); - expect(validated.events[0].http.request).to.equal(undefined); expect(validated.events[0].http.response).to.equal(undefined); + expect(validated.events[0].http.request.parameters).to.deep.equal({ + 'method.request.path.foo': true, + }); }); it('should throw an error when an invalid integration type was provided', () => {