Repository: stripe/stripe-node
Pull request #691 (2019-09-06 20:39:06)

GET and DELETE requests data: body->queryParams
r? @ob-stripe 
cc? @rattrayalex-stripe @remi-stripe 

Addresses #690 -- whenever an ApiResource method is called that corresponds to a GET or DELETE, those properties are attached to the end of the path.

I think this should be safe, assuming:
1. "Path" never already contains a query string.
2. No users are sending bodies large enough to risk hitting some sort of URL length limit.

I also changed `mocha.opts` not to bail by default. Rationale: I couldn't find a way to override this from the command-line (but it's easy to add `-b` if that's what you want), and I prefer not-bailing in cases where I need to make simple changes in many tests.



Patch:
diff --git a/lib/StripeMethod.js b/lib/StripeMethod.js
index ace8febf..22f75d45 100644
--- a/lib/StripeMethod.js
+++ b/lib/StripeMethod.js
@@ -47,3 +47,5 @@ function stripeMethod(spec) {
 }
 
 module.exports = stripeMethod;
+
+module.exports = stripeMethod;
diff --git a/lib/makeRequest.js b/lib/makeRequest.js
index c6b105b9..39d0b4b4 100644
--- a/lib/makeRequest.js
+++ b/lib/makeRequest.js
@@ -46,10 +46,15 @@ function getRequestOpts(self, requestArgs, spec, overrideData) {
     spec.validator(data, {headers});
   }
 
+  const dataInQuery = spec.method === 'GET' || spec.method === 'DELETE';
+  const bodyData = dataInQuery ? {} : data;
+  const queryData = dataInQuery ? data : {};
+
   return {
     requestMethod,
     requestPath,
-    data,
+    bodyData,
+    queryData,
     auth: options.auth,
     headers,
     host,
@@ -77,11 +82,18 @@ function makeRequest(self, requestArgs, spec, overrideData) {
       }
     }
 
+    const emptyQuery = Object.keys(opts.queryData).length === 0;
+    const path = [
+      opts.requestPath,
+      emptyQuery ? '' : '?',
+      utils.stringifyRequestData(opts.queryData),
+    ].join('');
+
     self._request(
       opts.requestMethod,
       opts.host,
-      opts.requestPath,
-      opts.data,
+      path,
+      opts.bodyData,
       opts.auth,
       {headers: opts.headers},
       requestCallback


Test patch:
diff --git a/test/StripeResource.spec.js b/test/StripeResource.spec.js
index 6aea57b8..6c60c2fd 100644
--- a/test/StripeResource.spec.js
+++ b/test/StripeResource.spec.js
@@ -48,21 +48,27 @@ describe('StripeResource', () => {
     });
 
     describe('_request', () => {
-      it('encodes the body in GET requests', (done) => {
+      it('encodes data for GET requests as query params', (done) => {
+        const data = {
+          customer: 'cus_123',
+          subscription_items: [
+            {plan: 'foo', quantity: 2},
+            {id: 'si_123', deleted: true},
+          ],
+        };
         const options = {
           host: stripe.getConstant('DEFAULT_HOST'),
           path: '/v1/invoices/upcoming',
-          data: {
-            customer: 'cus_123',
-            subscription_items: [
-              {plan: 'foo', quantity: 2},
-              {id: 'si_123', deleted: true},
-            ],
-          },
+          data,
         };
 
         const scope = nock(`https://${options.host}`)
-          .get(options.path, options.data)
+          .get(
+            `${
+              options.path
+            }?customer=cus_123&subscription_items[0][plan]=foo&subscription_items[0][quantity]=2&subscription_items[1][id]=si_123&subscription_items[1][deleted]=true`,
+            ''
+          )
           .reply(200, '{}');
 
         realStripe.invoices.retrieveUpcoming(options.data, (err, response) => {
@@ -71,6 +77,22 @@ describe('StripeResource', () => {
         });
       });
 
+      it('encodes data for DELETE requests as query params', (done) => {
+        const data = {
+          foo: 'bar',
+        };
+        const host = stripe.getConstant('DEFAULT_HOST');
+
+        const scope = nock(`https://${host}`)
+          .delete(/.*/)
+          .reply(200, '{}');
+
+        realStripe.invoiceItems.del('invoiceItemId1', data, (err, response) => {
+          done(err);
+          scope.done();
+        });
+      });
+
       it('encodes the body in POST requests', (done) => {
         const options = {
           host: stripe.getConstant('DEFAULT_HOST'),
diff --git a/test/mocha.opts b/test/mocha.opts
index 6ea60f64..4a523201 100644
--- a/test/mocha.opts
+++ b/test/mocha.opts
@@ -1,2 +1,1 @@
---bail
 --recursive
diff --git a/test/resources/BitcoinReceivers.spec.js b/test/resources/BitcoinReceivers.spec.js
index 494840c1..90935955 100644
--- a/test/resources/BitcoinReceivers.spec.js
+++ b/test/resources/BitcoinReceivers.spec.js
@@ -35,11 +35,9 @@ describe('BitcoinReceivers Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/bitcoin/receivers/receiverId/transactions',
+        url: '/v1/bitcoin/receivers/receiverId/transactions?limit=1',
         headers: {},
-        data: {
-          limit: 1,
-        },
+        data: {},
       });
     });
   });
diff --git a/test/resources/CreditNotes.spec.js b/test/resources/CreditNotes.spec.js
index 025e01a1..7cb01ce3 100644
--- a/test/resources/CreditNotes.spec.js
+++ b/test/resources/CreditNotes.spec.js
@@ -38,9 +38,9 @@ describe('CreditNotes Resource', () => {
       stripe.creditNotes.list({count: 25});
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/credit_notes',
+        url: '/v1/credit_notes?count=25',
         headers: {},
-        data: {count: 25},
+        data: {},
       });
     });
   });
diff --git a/test/resources/Events.spec.js b/test/resources/Events.spec.js
index 28fbe98e..455478a3 100644
--- a/test/resources/Events.spec.js
+++ b/test/resources/Events.spec.js
@@ -21,9 +21,9 @@ describe('Events Resource', () => {
       stripe.events.list({count: 25});
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/events',
+        url: '/v1/events?count=25',
         headers: {},
-        data: {count: 25},
+        data: {},
       });
     });
   });
diff --git a/test/resources/Invoices.spec.js b/test/resources/Invoices.spec.js
index 4a714c40..fe84e835 100644
--- a/test/resources/Invoices.spec.js
+++ b/test/resources/Invoices.spec.js
@@ -33,9 +33,9 @@ describe('Invoices Resource', () => {
       stripe.invoices.list({count: 25});
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/invoices',
+        url: '/v1/invoices?count=25',
         headers: {},
-        data: {count: 25},
+        data: {},
       });
     });
   });
@@ -97,12 +97,10 @@ describe('Invoices Resource', () => {
 
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/invoices/upcoming',
+        url:
+          '/v1/invoices/upcoming?customer=cus_abc&subscription_items[0][plan]=potato&subscription_items[1][plan]=rutabaga',
         headers: {},
-        data: {
-          customer: 'cus_abc',
-          subscription_items: [{plan: 'potato'}, {plan: 'rutabaga'}],
-        },
+        data: {},
       });
     });
   });
@@ -117,13 +115,10 @@ describe('Invoices Resource', () => {
 
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/invoices/upcoming/lines',
+        url:
+          '/v1/invoices/upcoming/lines?customer=cus_abc&subscription_items[0][plan]=potato&subscription_items[1][plan]=rutabaga&limit=5',
         headers: {},
-        data: {
-          customer: 'cus_abc',
-          subscription_items: [{plan: 'potato'}, {plan: 'rutabaga'}],
-          limit: 5,
-        },
+        data: {},
       });
     });
   });
diff --git a/test/resources/OrderReturns.spec.js b/test/resources/OrderReturns.spec.js
index f39052ed..7f7fe99d 100644
--- a/test/resources/OrderReturns.spec.js
+++ b/test/resources/OrderReturns.spec.js
@@ -23,10 +23,8 @@ describe('OrderReturn Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/order_returns',
-        data: {
-          limit: 3,
-        },
+        url: '/v1/order_returns?limit=3',
+        data: {},
         headers: {},
       });
     });
@@ -37,11 +35,9 @@ describe('OrderReturn Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/order_returns',
-        data: {
-          order: 'orderIdFoo123',
-        },
+        url: '/v1/order_returns?order=orderIdFoo123',
         headers: {},
+        data: {},
       });
     });
   });
diff --git a/test/resources/Orders.spec.js b/test/resources/Orders.spec.js
index c3672715..8b2c352e 100644
--- a/test/resources/Orders.spec.js
+++ b/test/resources/Orders.spec.js
@@ -65,10 +65,8 @@ describe('Order Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/orders',
-        data: {
-          limit: 3,
-        },
+        url: '/v1/orders?limit=3',
+        data: {},
         headers: {},
       });
     });
@@ -79,10 +77,8 @@ describe('Order Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/orders',
-        data: {
-          status: 'active',
-        },
+        url: '/v1/orders?status=active',
+        data: {},
         headers: {},
       });
     });
diff --git a/test/resources/PaymentMethods.spec.js b/test/resources/PaymentMethods.spec.js
index 0860c1cb..a9540498 100644
--- a/test/resources/PaymentMethods.spec.js
+++ b/test/resources/PaymentMethods.spec.js
@@ -40,9 +40,9 @@ describe('PaymentMethods Resource', () => {
       stripe.paymentMethods.list(data);
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/payment_methods',
+        url: '/v1/payment_methods?customer=cus_123&type=card',
         headers: {},
-        data,
+        data: {},
       });
     });
   });
diff --git a/test/resources/Products.spec.js b/test/resources/Products.spec.js
index 21c61935..78cba35b 100644
--- a/test/resources/Products.spec.js
+++ b/test/resources/Products.spec.js
@@ -43,10 +43,8 @@ describe('Product Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/products',
-        data: {
-          limit: 3,
-        },
+        url: '/v1/products?limit=3',
+        data: {},
         headers: {},
       });
     });
@@ -57,10 +55,8 @@ describe('Product Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/products',
-        data: {
-          shippable: true,
-        },
+        url: '/v1/products?shippable=true',
+        data: {},
         headers: {},
       });
     });
diff --git a/test/resources/Radar/ValueListItems.spec.js b/test/resources/Radar/ValueListItems.spec.js
index 286ef956..5d25722a 100644
--- a/test/resources/Radar/ValueListItems.spec.js
+++ b/test/resources/Radar/ValueListItems.spec.js
@@ -44,11 +44,9 @@ describe('Radar', () => {
         });
         expect(stripe.LAST_REQUEST).to.deep.equal({
           method: 'GET',
-          url: '/v1/radar/value_list_items',
+          url: '/v1/radar/value_list_items?value_list=rsl_123',
           headers: {},
-          data: {
-            value_list: 'rsl_123',
-          },
+          data: {},
         });
       });
     });
diff --git a/test/resources/SKUs.spec.js b/test/resources/SKUs.spec.js
index 5155d8fe..c397c529 100644
--- a/test/resources/SKUs.spec.js
+++ b/test/resources/SKUs.spec.js
@@ -47,10 +47,8 @@ describe('SKU Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/skus',
-        data: {
-          limit: 3,
-        },
+        url: '/v1/skus?limit=3',
+        data: {},
         headers: {},
       });
     });
@@ -61,10 +59,8 @@ describe('SKU Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/skus',
-        data: {
-          product: 'prodId123',
-        },
+        url: '/v1/skus?product=prodId123',
+        data: {},
         headers: {},
       });
     });
diff --git a/test/resources/SubscriptionItems.spec.js b/test/resources/SubscriptionItems.spec.js
index 56ba399e..4a6d1cde 100644
--- a/test/resources/SubscriptionItems.spec.js
+++ b/test/resources/SubscriptionItems.spec.js
@@ -71,12 +71,9 @@ describe('SubscriptionItems Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/subscription_items',
+        url: '/v1/subscription_items?limit=3&subscription=test_sub',
         headers: {},
-        data: {
-          limit: 3,
-          subscription: 'test_sub',
-        },
+        data: {},
       });
     });
   });
diff --git a/test/resources/Subscriptions.spec.js b/test/resources/Subscriptions.spec.js
index d1f76312..5575c848 100644
--- a/test/resources/Subscriptions.spec.js
+++ b/test/resources/Subscriptions.spec.js
@@ -178,13 +178,9 @@ describe('subscriptions Resource', () => {
       });
       expect(stripe.LAST_REQUEST).to.deep.equal({
         method: 'GET',
-        url: '/v1/subscriptions',
+        url: '/v1/subscriptions?limit=3&customer=test_cus&plan=gold',
         headers: {},
-        data: {
-          limit: 3,
-          customer: 'test_cus',
-          plan: 'gold',
-        },
+        data: {},
       });
     });
   });