Repository: serverless/serverless (JavaScript)
Date: 2018-07-25 16:29:23+00:00
Task type: Bug Fix

Issue:
ServerlessError: req.send is not a function
<!--
1. If you have a question and not a bug/feature request please ask it at http://forum.serverless.com
2. Please check if an issue already exists so there are no duplicates
3. Check out and follow our Guidelines: https://github.com/serverless/serverless/blob/master/CONTRIBUTING.md
4. Fill out the whole template so we have a good overview on the issue
5. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the Issue
6. Please follow the template, otherwise we'll have to ask you to update it
-->

# This is a Bug Report

## Description

For bug reports:
* What went wrong?
this.provider = this.serverless.getProvider(this.serverless.service.provider.name)
this.provider.request('APIGateway', 'getRestApis', {})
throws an error 'req.send is not a function'

* What did you expect should have happened?
Should have executed the aws call and returned list of restApis.

* What was the config you used?
default

* What stacktrace or error message from your provider did you see?
ServerlessError: req.send is not a function
    at BbPromise.fromCallback.catch.err (node_modules/serverless/lib/plugins/aws/provider/awsProvider.js:270:11)
    at tryCatcher (node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromiseCtx (node_modules/bluebird/js/release/promise.js:606:10)
    at Async._drainQueue (node_modules/bluebird/js/release/async.js:138:12)
    at Async._drainQueues (node_modules/bluebird/js/release/async.js:143:10)
    at Immediate.Async.drainQueues [as _onImmediate] (node_modules/bluebird/js/release/async.js:17:14)
    at process.topLevelDomainCallback (domain.js:121:23)

## Additional Data

* ***Serverless Framework Version you're using***: 1.26.0
* ***Operating System***: OSX
* ***Stack Trace***: ServerlessError: req.send is not a function
* ***Provider Error messages***: N/A



Issue discussion:

Solution patch:
diff --git a/lib/plugins/aws/provider/awsProvider.js b/lib/plugins/aws/provider/awsProvider.js
index fde827ffcb6..64a090d3027 100644
--- a/lib/plugins/aws/provider/awsProvider.js
+++ b/lib/plugins/aws/provider/awsProvider.js
@@ -271,10 +271,10 @@ class AwsProvider {
       // TODO: Add listeners, put Debug statments here...
       // req.on('send', function (r) {console.log(r)});
 
-      return BbPromise.fromCallback(cb => {
+      const promise = req.promise ? req.promise() : BbPromise.fromCallback(cb => {
         req.send(cb);
-      })
-      .catch(err => {
+      });
+      return promise.catch(err => {
         let message = err.message;
         if (err.message === 'Missing credentials in config') {
           const errorMessage = [


Test patch:
diff --git a/lib/plugins/aws/provider/awsProvider.test.js b/lib/plugins/aws/provider/awsProvider.test.js
index d736f83141d..914f110b845 100644
--- a/lib/plugins/aws/provider/awsProvider.test.js
+++ b/lib/plugins/aws/provider/awsProvider.test.js
@@ -98,7 +98,7 @@ describe('AwsProvider', () => {
         '${opt:stage, \'prod\'}',
       ];
       stages.forEach(stage => {
-        it(`should not throw an error before variable population 
+        it(`should not throw an error before variable population
             even if http event is present and stage is ${stage}`, () => {
           const config = {
             stage,
@@ -286,6 +286,39 @@ describe('AwsProvider', () => {
       });
     });
 
+    it('should call correct aws method with a promise', () => {
+      // mocking API Gateway for testing
+      class FakeAPIGateway {
+        constructor(credentials) {
+          this.credentials = credentials;
+        }
+
+        getRestApis() {
+          return {
+            promise: () => BbPromise.resolve({ called: true }),
+          };
+        }
+      }
+      awsProvider.sdk = {
+        APIGateway: FakeAPIGateway,
+      };
+      awsProvider.serverless.service.environment = {
+        vars: {},
+        stages: {
+          dev: {
+            vars: {
+              profile: 'default',
+            },
+            regions: {},
+          },
+        },
+      };
+
+      return awsProvider.request('APIGateway', 'getRestApis', {}).then(data => {
+        expect(data.called).to.equal(true);
+      });
+    });
+
 
     it('should request to the specified region if region in options set', () => {
       // mocking S3 for testing
@@ -316,7 +349,7 @@ describe('AwsProvider', () => {
           },
         },
       };
-      expect(awsProvider.getCredentials()).to.deep.eql({ region: options.region });
+      expect(awsProvider.getCredentials().region).to.eql(options.region);
 
       return awsProvider
         .request('CloudFormation',
@@ -326,7 +359,7 @@ describe('AwsProvider', () => {
         .then(data => {
           expect(data).to.eql({ region: 'ap-northeast-1' });
           // Requesting different region should not affect region in credentials
-          expect(awsProvider.getCredentials()).to.deep.eql({ region: options.region });
+          expect(awsProvider.getCredentials().region).to.eql(options.region);
         });
     });
     it('should retry if error code is 429', (done) => {