Repository: serverless/serverless (JavaScript)
Date: 2017-06-01 15:27:52+00:00
Task type: Feature

Issue:
Return error when lambda-proxy and req/res config user
# This is a Feature Proposal

Follow up of https://github.com/serverless/serverless/pull/2799#issuecomment-265400880. We should return error if both lambda-proxy and req/res config is used to reduce confusion.



Issue discussion:
Counterpoint: https://github.com/serverless/serverless/issues/2990

Solution patch:
diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md
index 79f7a7c0f22..3f7022f9964 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 13ab37913c7..1d7e55b9d34 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',
       ];


Test patch:
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 6206c757b5a..6e9c6a12b1b 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', () => {