diff --git a/README.md b/README.md index 40b245d..5fec9ff 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ Create a new instance of the Netlify API client with the provided `accessToken`. host: 'api.netlify.com', pathPrefix: '/api/v1', accessToken: '1234myAccessToken', + agent: undefined, // e.g. HttpsProxyAgent globalParams: {} // parameters you want available for every request. // Global params are only sent of the OpenAPI spec specifies the provided params. } @@ -192,6 +193,18 @@ Optional `opts` include: } ``` +## Proxy support + +**Node.js only**: If this client is used behind a corporate proxy, you can pass an `HttpsProxyAgent` or any other `http.Agent` that can handle your situation as `agent` option: + +```js +const HttpsProxyAgent = require('https-proxy-agent') + +const proxyUri = 'http(s)://[user:password@]proxyhost:port' +const agent = new HttpsProxyAgent(proxyUri) +const client = new NetlifyAPI('1234myAccessToken', { agent }) +``` + ## UMD Builds A UMD build is provided for your convenience, however browser support is still experimental. Contributions to improve browser support are welcome. diff --git a/src/index.js b/src/index.js index a392180..56bc328 100644 --- a/src/index.js +++ b/src/index.js @@ -39,6 +39,7 @@ class NetlifyAPI { this.pathPrefix = opts.pathPrefix this.globalParams = opts.globalParams this.accessToken = opts.accessToken + this.agent = opts.agent } get accessToken() { diff --git a/src/index.test.js b/src/index.test.js index 1c68122..e7f38d8 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -1,3 +1,5 @@ +const http = require('http') + const test = require('ava') const fromString = require('from2-string') const { TextHTTPError, JSONHTTPError } = require('micro-api-client') @@ -12,6 +14,13 @@ const pathPrefix = '/api/v10' const host = `${domain}:${port}` const origin = `${scheme}://${host}` const accessToken = 'testAccessToken' +const agent = new http.Agent({ + keepAlive: true, + keepAliveMsecs: 60000, + maxSockets: 10, + maxFreeSockets: 10, + timeout: 60000 +}) const getClient = function(opts = {}) { return new NetlifyAPI(opts.accessToken, Object.assign({ scheme, host, pathPrefix }, opts)) @@ -23,6 +32,7 @@ test('Default options', async t => { t.is(client.host, 'api.netlify.com') t.is(client.pathPrefix, '/api/v1') t.is(client.accessToken, null) + t.is(client.agent, undefined) t.deepEqual(client.globalParams, {}) t.deepEqual(client.defaultHeaders, { 'User-agent': 'netlify/js-client', @@ -543,5 +553,32 @@ test('Gives up retrying on API rate limiting after a timeout', async t => { t.false(scope.isDone()) }) +test('Can set (proxy) agent', async t => { + const client = getClient({ accessToken, agent }) + t.is(client.agent, agent) +}) + +test('(Proxy) agent is passed as request option', async t => { + const account_id = '15' + const scope = nock(origin) + .get(`${pathPrefix}/accounts/${account_id}`) + .reply(200) + + const client = getClient({ accessToken, agent }) + await client.getAccount({ account_id }) + t.is(scope.interceptors[0].req.options.agent, agent) +}) + +test('(Proxy) agent is not passed as request option if not set', async t => { + const account_id = '15' + const scope = nock(origin) + .get(`${pathPrefix}/accounts/${account_id}`) + .reply(200) + + const client = getClient({ accessToken }) + await client.getAccount({ account_id }) + t.falsy(scope.interceptors[0].req.options.agent) +}) + const TEST_RATE_LIMIT_DELAY = 5e3 const SECS_TO_MSECS = 1e3 diff --git a/src/methods/index.js b/src/methods/index.js index 8ff5c8e..e5cd640 100644 --- a/src/methods/index.js +++ b/src/methods/index.js @@ -43,7 +43,8 @@ const getOpts = function({ verb, parameters }, NetlifyApi, { body }, opts) { const optsA = addHttpMethod(verb, opts) const optsB = addDefaultHeaders(NetlifyApi, optsA) const optsC = addBody(body, parameters, optsB) - return optsC + const optsD = addAgent(NetlifyApi, optsC) + return optsD } // Add the HTTP method based on the OpenAPI definition @@ -58,6 +59,15 @@ const addDefaultHeaders = function(NetlifyApi, opts) { }) } +// Assign fetch agent (like for example HttpsProxyAgent) if there is one +const addAgent = function(NetlifyApi, opts) { + if (NetlifyApi.agent) { + return Object.assign({}, opts, { agent: NetlifyApi.agent }) + } else { + return opts + } +} + const makeRequestOrRetry = async function(url, opts) { for (let index = 0; index <= MAX_RETRY; index++) { const response = await makeRequest(url, opts)