Skip to content

Commit

Permalink
New config object (#703)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulasjes-stripe authored and rattrayalex-stripe committed Nov 7, 2019
1 parent a22a77a commit 265827e
Show file tree
Hide file tree
Showing 70 changed files with 925 additions and 110 deletions.
84 changes: 77 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,36 @@ const stripe = Stripe('sk_test_...');
On older versions of Node, you can use [promises](#using-promises)
or [callbacks](#using-callbacks) instead of `async`/`await`.

## Initialize with config object

The package can be initialized with several options:

```js
import ProxyAgent from 'https-proxy-agent';

const stripe = Stripe('sk_test_...', {
apiVersion: '2019-08-08',
maxNetworkRetries: 1,
httpAgent: new ProxyAgent(process.env.http_proxy),
timeout: 1000,
host: 'api.example.com',
port: 123,
telemetry: true,
});
```

| Option | Default | Description |
| ------------------- | ----------------------------- | ------------------------------------------------------------------------------------- |
| `apiVersion` | `null` | Stripe API version to be used. If not set the account's default version will be used. |
| `maxNetworkRetries` | 0 | The amount of times a request should be [retried](#network-retries). |
| `httpAgent` | `null` | [Proxy](#configuring-a-proxy) agent to be used by the library. |
| `timeout` | 120000 (Node default timeout) | [Maximum time each request can take in ms.](#configuring-timeout) |
| `host` | `'api.stripe.com'` | Host that requests are made to. |
| `port` | 443 | Port that requests are made to. |
| `telemetry` | `true` | Allow Stripe to send latency [telemetry](#request-latency-telemetry) |

Note: Both `maxNetworkRetries` and `timeout` can be overridden on a per-request basis. `timeout` can be updated at any time with [`stripe.setTimeout`](#configuring-timeout).

### Usage with TypeScript

Stripe does not currently maintain typings for this package, but there are
Expand Down Expand Up @@ -135,6 +165,29 @@ Request timeout is configurable (the default is Node's default of 120 seconds):
stripe.setTimeout(20000); // in ms (this is 20 seconds)
```

Timeout can also be set globally via the config object:

```js
const stripe = Stripe('sk_test_...', {
timeout: 2000,
});
```

And on a per-request basis:

```js
stripe.customers.create(
{
email: 'customer@example.com',
},
{
timeout: 1000,
}
);
```

If `timeout` is set globally via the config object, the value set in a per-request basis will be favored.

### Configuring For Connect

A per-request `Stripe-Account` header for use with [Stripe Connect][connect]
Expand All @@ -144,7 +197,7 @@ can be added to any method:
// Retrieve the balance for a connected account:
stripe.balance
.retrieve({
stripe_account: 'acct_foo',
stripeAccount: 'acct_foo',
})
.then((balance) => {
// The balance object for the connected account
Expand All @@ -159,24 +212,41 @@ stripe.balance
An [https-proxy-agent][https-proxy-agent] can be configured with
`setHttpAgent`.

To use stripe behind a proxy you can pass to sdk:
To use stripe behind a proxy you can pass to sdk on initialization:

```js
if (process.env.http_proxy) {
const ProxyAgent = require('https-proxy-agent');
stripe.setHttpAgent(new ProxyAgent(process.env.http_proxy));

const stripe = Stripe('sk_test_...', {
httpProxy: new ProxyAgent(process.env.http_proxy),
});
}
```

### Network retries

Automatic network retries can be enabled with `setMaxNetworkRetries`.
Automatic network retries can be enabled with the `maxNetworkRetries` config option.
This will retry requests `n` times with exponential backoff if they fail due to an intermittent network problem.
[Idempotency keys](https://stripe.com/docs/api/idempotent_requests) are added where appropriate to prevent duplication.

```js
// Retry a request twice before giving up
stripe.setMaxNetworkRetries(2);
const stripe = Stripe('sk_test_...', {
maxNetworkRetries: 2, // Retry a request twice before giving up
});
```

Network retries can also be set on a per-request basis:

```js
stripe.customers.create(
{
email: 'customer@example.com',
},
{
maxNetworkRetries: 2, // Retry this specific request twice before giving up
}
);
```

### Examining Responses
Expand All @@ -185,7 +255,7 @@ Some information about the response which generated a resource is available
with the `lastResponse` property:

```js
charge.lastResponse.requestId; // see: https://stripe.com/docs/api/node#request_ids
charge.lastResponse.requestId; // see: https://stripe.com/docs/api/request_ids?lang=node
charge.lastResponse.statusCode;
```

Expand Down
46 changes: 35 additions & 11 deletions lib/StripeResource.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,9 @@ StripeResource.prototype = {
},

// For more on when and how to retry API requests, see https://stripe.com/docs/error-handling#safely-retrying-requests-with-idempotency
_shouldRetry(res, numRetries) {
_shouldRetry(res, numRetries, maxRetries) {
// Do not retry if we are out of retries.
if (numRetries >= this._stripe.getMaxNetworkRetries()) {
if (numRetries >= maxRetries) {
return false;
}

Expand Down Expand Up @@ -283,9 +283,19 @@ StripeResource.prototype = {
return sleepSeconds * 1000;
},

_defaultIdempotencyKey(method) {
// Max retries can be set on a per request basis. Favor those over the global setting
_getMaxNetworkRetries(settings = {}) {
return settings.maxNetworkRetries &&
Number.isInteger(settings.maxNetworkRetries)
? settings.maxNetworkRetries
: this._stripe.getMaxNetworkRetries();
},

_defaultIdempotencyKey(method, settings) {
// If this is a POST and we allow multiple retries, ensure an idempotency key.
if (method === 'POST' && this._stripe.getMaxNetworkRetries() > 0) {
const maxRetries = this._getMaxNetworkRetries(settings);

if (method === 'POST' && maxRetries > 0) {
return `stripe-node-retry-${utils.uuid4()}`;
}
return null;
Expand All @@ -297,7 +307,8 @@ StripeResource.prototype = {
apiVersion,
clientUserAgent,
method,
userSuppliedHeaders
userSuppliedHeaders,
userSuppliedSettings
) {
const defaultHeaders = {
// Use specified auth token or use default from this stripe instance:
Expand All @@ -309,7 +320,10 @@ StripeResource.prototype = {
'X-Stripe-Client-User-Agent': clientUserAgent,
'X-Stripe-Client-Telemetry': this._getTelemetryHeader(),
'Stripe-Version': apiVersion,
'Idempotency-Key': this._defaultIdempotencyKey(method),
'Idempotency-Key': this._defaultIdempotencyKey(
method,
userSuppliedSettings
),
};

return Object.assign(
Expand Down Expand Up @@ -358,7 +372,7 @@ StripeResource.prototype = {
}
},

_request(method, host, path, data, auth, options, callback) {
_request(method, host, path, data, auth, options = {}, callback) {
let requestData;

const retryRequest = (
Expand All @@ -378,7 +392,14 @@ StripeResource.prototype = {
};

const makeRequest = (apiVersion, headers, numRetries) => {
const timeout = this._stripe.getApiField('timeout');
// timeout can be set on a per-request basis. Favor that over the global setting
const timeout =
options.settings &&
Number.isInteger(options.settings.timeout) &&
options.settings.timeout >= 0
? options.settings.timeout
: this._stripe.getApiField('timeout');

const isInsecureConnection =
this._stripe.getApiField('protocol') == 'http';
let agent = this._stripe.getApiField('agent');
Expand Down Expand Up @@ -409,6 +430,8 @@ StripeResource.prototype = {

const requestRetries = numRetries || 0;

const maxRetries = this._getMaxNetworkRetries(options.settings);

req._requestEvent = requestEvent;

req._requestStart = requestStartTime;
Expand All @@ -418,7 +441,7 @@ StripeResource.prototype = {
req.setTimeout(timeout, this._timeoutHandler(timeout, req, callback));

req.once('response', (res) => {
if (this._shouldRetry(res, requestRetries)) {
if (this._shouldRetry(res, requestRetries, maxRetries)) {
return retryRequest(
makeRequest,
apiVersion,
Expand All @@ -432,7 +455,7 @@ StripeResource.prototype = {
});

req.on('error', (error) => {
if (this._shouldRetry(null, requestRetries)) {
if (this._shouldRetry(null, requestRetries, maxRetries)) {
return retryRequest(
makeRequest,
apiVersion,
Expand Down Expand Up @@ -478,7 +501,8 @@ StripeResource.prototype = {
apiVersion,
clientUserAgent,
method,
options.headers
options.headers,
options.settings
);

makeRequest(apiVersion, headers);
Expand Down
5 changes: 4 additions & 1 deletion lib/makeRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ function getRequestOpts(self, requestArgs, spec, overrideData) {
auth: options.auth,
headers,
host,
settings: options.settings,
};
}

Expand Down Expand Up @@ -89,13 +90,15 @@ function makeRequest(self, requestArgs, spec, overrideData) {
utils.stringifyRequestData(opts.queryData),
].join('');

const {headers, settings} = opts;

self._request(
opts.requestMethod,
opts.host,
path,
opts.bodyData,
opts.auth,
{headers: opts.headers},
{headers, settings},
requestCallback
);
});
Expand Down
Loading

0 comments on commit 265827e

Please sign in to comment.