From b76a15205aae7f7a66de8cbb7b378622525ad829 Mon Sep 17 00:00:00 2001 From: Simon Tanner Date: Tue, 15 Aug 2023 15:54:52 +0100 Subject: [PATCH 01/69] chore: use node-fetch wip --- .nvmrc | 1 + lib/client.js | 2 + lib/transport/request.js | 21 +- package.json | 6 +- test/callbacks/client.js | 660 +++++++++++++++++++-------------------- test/client.js | 3 +- 6 files changed, 353 insertions(+), 340 deletions(-) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..25bf17f --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18 \ No newline at end of file diff --git a/lib/client.js b/lib/client.js index de1afae..e0cabc2 100644 --- a/lib/client.js +++ b/lib/client.js @@ -285,10 +285,12 @@ class HttpTransportClient { * */ async asResponse() { + console.log('asResponse') const currentContext = this._ctx; this._initContext(); const ctx = await retry(this._executeRequest, currentContext); + console.log('ctx: ', ctx) return ctx.res; } diff --git a/lib/transport/request.js b/lib/transport/request.js index e9f5065..9c27f01 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -1,10 +1,11 @@ 'use strict'; const _ = require('lodash'); -const promisifyAll = require('./promiseUtils').promisifyAll; +// const promisifyAll = require('./promiseUtils').promisifyAll; const Transport = require('./transport'); -const Request = require('request'); +const Request = require('request-promise-native'); const dns = require('dns'); +const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const REQUIRED_PROPERTIES = [ 'body', @@ -14,14 +15,15 @@ const REQUIRED_PROPERTIES = [ 'headers' ]; -function toAsyncMethod(method) { - return `${method.toLowerCase()}Async`; -} +// function toAsyncMethod(method) { +// return `${method.toLowerCase()}Async`; +// } class RequestTransport extends Transport { constructor(customRequest) { super(); - this._request = promisifyAll(customRequest || Request); + this._request = customRequest || fetch; + console.log("🚀 ~ file: request.js:25 ~ RequestTransport ~ constructor ~ Request:", Request) } toOptions(ctx) { @@ -64,9 +66,14 @@ class RequestTransport extends Transport { } makeRequest(ctx, opts) { + console.log('opts', opts) + console.log('ctx: ', ctx) const url = ctx.req.getUrl(); const method = ctx.req.getMethod(); - return this._request[toAsyncMethod(method)](url, opts); + console.log('method', method) + console.log('this._request', this._request) + opts.method = method + return this._request(url, opts); } } diff --git a/package.json b/package.json index 627159c..aca9774 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "url": "https://github.com/bbc/http-transport/issues" }, "engines": { - "node": ">=8.0.0" + "node": ">=18.0.0" }, "keywords": [ "https", @@ -52,8 +52,10 @@ "bluebird": "^3.5.0", "koa-compose": "^4.0.0", "lodash": "^4.17.4", + "node-fetch": "^3.3.2", "qs": "^6.5.1", - "request": "^2.88.0" + "request": "^2.88.0", + "request-promise-native": "^1.0.9" }, "mocha": { "recursive": true, diff --git a/test/callbacks/client.js b/test/callbacks/client.js index 48c51e5..83d4033 100644 --- a/test/callbacks/client.js +++ b/test/callbacks/client.js @@ -32,334 +32,334 @@ function nockRetries(retry, opts) { } describe('CallbackDecorator', () => { - let httpTransport; - - beforeEach(() => { - httpTransport = HttpTransport.createClient(); - nock.disableNetConnect(); - nock.cleanAll(); - api.get(path).reply(200, simpleResponseBody); - }); - - it('decorates an instance of HttpTransport', (done) => { - nock.cleanAll(); - - nock(host) - .get(path) - .reply(200, 'the test passes'); - - new CallbackDecorator(httpTransport) - .get(url) - .asResponse((err, res) => { - assert.ifError(err); - assert.equal(res.statusCode, 200); - assert.equal(res.body, 'the test passes'); - done(); - }); - }); - - describe('.get', () => { - it('returns a response', (done) => { - new CallbackDecorator(httpTransport) - .get(url) - .asResponse((err, res) => { - assert.ifError(err); - assert.equal(res.body, simpleResponseBody); - done(); - }); - }); - - it('sets a default User-agent', (done) => { - nock.cleanAll(); - - const HeaderValue = `${packageInfo.name}/${packageInfo.version}`; - nock(host, { - reqheaders: { - 'User-Agent': HeaderValue - } - }) - .get(path) - .reply(200, responseBody); - - new CallbackDecorator(httpTransport) - .get(url) - .asResponse(() => { - done(); - }); - }); - - it('throws if a plugin is not a function', () => { - assert.throws( - () => { - HttpTransport.createBuilder() - .use('bad plugin') - .asCallback(httpTransport); - }, - TypeError, - 'Plugin is not a function' - ); - }); - }); - - describe('timeout', () => { - it('sets the timeout', (done) => { - nock.cleanAll(); - api - .get('/') - .delay(1000) - .reply(200, simpleResponseBody); - - const client = new CallbackDecorator(httpTransport); - client - .get(url) - .timeout(20) - .asBody((err) => { - assert.equal(err, 'Error: Request failed for GET http://www.example.com/: ESOCKETTIMEDOUT'); - done(); - }); - }); - }); - - describe('.retries', () => { - it('retries a given number of times for failed requests', (done) => { - nockRetries(2); - new CallbackDecorator(httpTransport) - .use(toError()) - .get(url) - .retry(2) - .asResponse((err, res) => { - assert.ifError(err); - assert.equal(res.statusCode, 200); - done(); - }); - }); - - it('waits a minimum of 100ms between retries by default', (done) => { - nockRetries(1); - const startTime = Date.now(); - - const client = HttpTransport.createBuilder() - .use(toError()) - .asCallback() - .createClient(); - - client - .get(url) - .retry(2) - .asResponse((err, res) => { - assert.ifError(err); - const timeTaken = Date.now() - startTime; - assert(timeTaken > 100); - assert.equal(res.statusCode, 200); - done(); - }); - }); - - it('overrides the minimum wait time between retries', (done) => { - nockRetries(1); - const retryDelay = 200; - const startTime = Date.now(); - - const client = HttpTransport.createBuilder() - .use(toError()) - .asCallback() - .createClient(); - - client - .get(url) - .retry(2) - .retryDelay(retryDelay) - .asResponse((err, res) => { - assert.ifError(err); - const timeTaken = Date.now() - startTime; - assert(timeTaken > retryDelay, 'Responded faster than expected'); - assert.equal(res.statusCode, 200); - done(); - }); - }); - }); - - describe('.post', () => { - it('makes a POST request', (done) => { - api.post(path, requestBody).reply(201, responseBody); - - new CallbackDecorator(httpTransport) - .post(url, requestBody) - .asBody((err, body) => { - assert.ifError(err); - assert.deepEqual(body, responseBody); - done(); - }); - }); - - it('returns an error when the API returns a 5XX status code', (done) => { - api.post(path, requestBody).reply(500); - - const client = HttpTransport.createBuilder(httpTransport) - .use(toError()) - .asCallback() - .createClient(); - - client.post(url, requestBody).asResponse((err) => { - assert.ok(err); - done(); - }); - }); - }); - - describe('.put', () => { - it('makes a PUT request with a JSON body', (done) => { - api.put(path, requestBody).reply(201, responseBody); - - new CallbackDecorator(httpTransport) - .put(url, requestBody) - .asBody((err, body) => { - assert.deepEqual(body, responseBody); - done(); - }); - }); - - it('returns an error when the API returns a 5XX status code', (done) => { - api.put(path, requestBody).reply(500); - - const client = HttpTransport.createBuilder(httpTransport) - .use(toError()) - .asCallback() - .createClient(); - - client.put(url, requestBody).asResponse((err) => { - assert.ok(err); - done(); - }); - }); - }); - - describe('.delete', () => { - it('makes a DELETE request', (done) => { - api.delete(path).reply(204); - new CallbackDecorator(httpTransport) - .delete(url) - .asResponse(done); - }); - - it('returns an error when the API returns a 5XX status code', (done) => { - api.delete(path).reply(500); - - new CallbackDecorator(httpTransport) - .delete(url) - .asResponse((err) => { - assert.ifError(err); - done(); - }); - }); - }); - - describe('.patch', () => { - it('makes a PATCH request', (done) => { - api.patch(path).reply(204); - new CallbackDecorator(httpTransport) - .patch(url) - .asResponse((err) => { - assert.ifError(err); - done(); - }); - }); - - it('returns an error when the API returns a 5XX status code', (done) => { - api.patch(path, requestBody).reply(500); - - new CallbackDecorator(httpTransport) - .patch(url, requestBody) - .asResponse((err) => { - assert.ifError(err); - done(); - }); - }); - }); - - describe('.head', () => { - it('makes a HEAD request', (done) => { - api.head(path).reply(200); - - new CallbackDecorator(httpTransport) - .head(url) - .asResponse((err, res) => { - assert.ifError(err); - assert.strictEqual(res.statusCode, 200); - done(); - }); - }); - - it('returns an error when the API returns a 5XX status code', (done) => { - api.head(path).reply(500); - - new CallbackDecorator(httpTransport) - .head(url) - .asResponse((err) => { - assert.ifError(err); - done(); - }); - }); - }); - - describe('.headers', () => { - it('sends custom headers', (done) => { - nock.cleanAll(); - - const HeaderValue = `${packageInfo.name}/${packageInfo.version}`; - nock(host, { - reqheaders: { - 'User-Agent': HeaderValue, - foo: 'bar' - } - }) - .get(path) - .reply(200, responseBody); - - new CallbackDecorator(httpTransport) - .get(url) - .headers({ - 'User-Agent': HeaderValue, - foo: 'bar' - }) - .asResponse((err, res) => { - assert.ifError(err); - assert.equal(res.statusCode, 200); - done(); - }); - }); - }); - - describe('query strings', () => { - it('supports adding a query string', (done) => { - api.get('/?a=1').reply(200, simpleResponseBody); - - new CallbackDecorator(httpTransport) - .get(url) - .query('a', 1) - .asBody((err, body) => { - assert.ifError(err); - assert.equal(body, simpleResponseBody); - done(); - }); - }); - - it('supports multiple query strings', (done) => { - nock.cleanAll(); - api.get('/?a=1&b=2&c=3').reply(200, simpleResponseBody); - - new CallbackDecorator(httpTransport) - .get(url) - .query({ - a: 1, - b: 2, - c: 3 - }) - .asBody((err, body) => { - assert.ifError(err); - assert.equal(body, simpleResponseBody); - done(); - }); - }); - }); + // let httpTransport; + + // beforeEach(() => { + // httpTransport = HttpTransport.createClient(); + // nock.disableNetConnect(); + // nock.cleanAll(); + // api.get(path).reply(200, simpleResponseBody); + // }); + + // it('decorates an instance of HttpTransport', (done) => { + // nock.cleanAll(); + + // nock(host) + // .get(path) + // .reply(200, 'the test passes'); + + // new CallbackDecorator(httpTransport) + // .get(url) + // .asResponse((err, res) => { + // assert.ifError(err); + // assert.equal(res.statusCode, 200); + // assert.equal(res.body, 'the test passes'); + // done(); + // }); + // }); + + // describe('.get', () => { + // it('returns a response', (done) => { + // new CallbackDecorator(httpTransport) + // .get(url) + // .asResponse((err, res) => { + // assert.ifError(err); + // assert.equal(res.body, simpleResponseBody); + // done(); + // }); + // }); + + // it('sets a default User-agent', (done) => { + // nock.cleanAll(); + + // const HeaderValue = `${packageInfo.name}/${packageInfo.version}`; + // nock(host, { + // reqheaders: { + // 'User-Agent': HeaderValue + // } + // }) + // .get(path) + // .reply(200, responseBody); + + // new CallbackDecorator(httpTransport) + // .get(url) + // .asResponse(() => { + // done(); + // }); + // }); + + // it('throws if a plugin is not a function', () => { + // assert.throws( + // () => { + // HttpTransport.createBuilder() + // .use('bad plugin') + // .asCallback(httpTransport); + // }, + // TypeError, + // 'Plugin is not a function' + // ); + // }); + // }); + + // describe('timeout', () => { + // it('sets the timeout', (done) => { + // nock.cleanAll(); + // api + // .get('/') + // .delay(1000) + // .reply(200, simpleResponseBody); + + // const client = new CallbackDecorator(httpTransport); + // client + // .get(url) + // .timeout(20) + // .asBody((err) => { + // assert.equal(err, 'Error: Request failed for GET http://www.example.com/: ESOCKETTIMEDOUT'); + // done(); + // }); + // }); + // }); + + // describe('.retries', () => { + // it('retries a given number of times for failed requests', (done) => { + // nockRetries(2); + // new CallbackDecorator(httpTransport) + // .use(toError()) + // .get(url) + // .retry(2) + // .asResponse((err, res) => { + // assert.ifError(err); + // assert.equal(res.statusCode, 200); + // done(); + // }); + // }); + + // it('waits a minimum of 100ms between retries by default', (done) => { + // nockRetries(1); + // const startTime = Date.now(); + + // const client = HttpTransport.createBuilder() + // .use(toError()) + // .asCallback() + // .createClient(); + + // client + // .get(url) + // .retry(2) + // .asResponse((err, res) => { + // assert.ifError(err); + // const timeTaken = Date.now() - startTime; + // assert(timeTaken > 100); + // assert.equal(res.statusCode, 200); + // done(); + // }); + // }); + + // it('overrides the minimum wait time between retries', (done) => { + // nockRetries(1); + // const retryDelay = 200; + // const startTime = Date.now(); + + // const client = HttpTransport.createBuilder() + // .use(toError()) + // .asCallback() + // .createClient(); + + // client + // .get(url) + // .retry(2) + // .retryDelay(retryDelay) + // .asResponse((err, res) => { + // assert.ifError(err); + // const timeTaken = Date.now() - startTime; + // assert(timeTaken > retryDelay, 'Responded faster than expected'); + // assert.equal(res.statusCode, 200); + // done(); + // }); + // }); + // }); + + // describe('.post', () => { + // it('makes a POST request', (done) => { + // api.post(path, requestBody).reply(201, responseBody); + + // new CallbackDecorator(httpTransport) + // .post(url, requestBody) + // .asBody((err, body) => { + // assert.ifError(err); + // assert.deepEqual(body, responseBody); + // done(); + // }); + // }); + + // it('returns an error when the API returns a 5XX status code', (done) => { + // api.post(path, requestBody).reply(500); + + // const client = HttpTransport.createBuilder(httpTransport) + // .use(toError()) + // .asCallback() + // .createClient(); + + // client.post(url, requestBody).asResponse((err) => { + // assert.ok(err); + // done(); + // }); + // }); + // }); + + // describe('.put', () => { + // it('makes a PUT request with a JSON body', (done) => { + // api.put(path, requestBody).reply(201, responseBody); + + // new CallbackDecorator(httpTransport) + // .put(url, requestBody) + // .asBody((err, body) => { + // assert.deepEqual(body, responseBody); + // done(); + // }); + // }); + + // it('returns an error when the API returns a 5XX status code', (done) => { + // api.put(path, requestBody).reply(500); + + // const client = HttpTransport.createBuilder(httpTransport) + // .use(toError()) + // .asCallback() + // .createClient(); + + // client.put(url, requestBody).asResponse((err) => { + // assert.ok(err); + // done(); + // }); + // }); + // }); + + // describe('.delete', () => { + // it('makes a DELETE request', (done) => { + // api.delete(path).reply(204); + // new CallbackDecorator(httpTransport) + // .delete(url) + // .asResponse(done); + // }); + + // it('returns an error when the API returns a 5XX status code', (done) => { + // api.delete(path).reply(500); + + // new CallbackDecorator(httpTransport) + // .delete(url) + // .asResponse((err) => { + // assert.ifError(err); + // done(); + // }); + // }); + // }); + + // describe('.patch', () => { + // it('makes a PATCH request', (done) => { + // api.patch(path).reply(204); + // new CallbackDecorator(httpTransport) + // .patch(url) + // .asResponse((err) => { + // assert.ifError(err); + // done(); + // }); + // }); + + // it('returns an error when the API returns a 5XX status code', (done) => { + // api.patch(path, requestBody).reply(500); + + // new CallbackDecorator(httpTransport) + // .patch(url, requestBody) + // .asResponse((err) => { + // assert.ifError(err); + // done(); + // }); + // }); + // }); + + // describe('.head', () => { + // it('makes a HEAD request', (done) => { + // api.head(path).reply(200); + + // new CallbackDecorator(httpTransport) + // .head(url) + // .asResponse((err, res) => { + // assert.ifError(err); + // assert.strictEqual(res.statusCode, 200); + // done(); + // }); + // }); + + // it('returns an error when the API returns a 5XX status code', (done) => { + // api.head(path).reply(500); + + // new CallbackDecorator(httpTransport) + // .head(url) + // .asResponse((err) => { + // assert.ifError(err); + // done(); + // }); + // }); + // }); + + // describe('.headers', () => { + // it('sends custom headers', (done) => { + // nock.cleanAll(); + + // const HeaderValue = `${packageInfo.name}/${packageInfo.version}`; + // nock(host, { + // reqheaders: { + // 'User-Agent': HeaderValue, + // foo: 'bar' + // } + // }) + // .get(path) + // .reply(200, responseBody); + + // new CallbackDecorator(httpTransport) + // .get(url) + // .headers({ + // 'User-Agent': HeaderValue, + // foo: 'bar' + // }) + // .asResponse((err, res) => { + // assert.ifError(err); + // assert.equal(res.statusCode, 200); + // done(); + // }); + // }); + // }); + + // describe('query strings', () => { + // it('supports adding a query string', (done) => { + // api.get('/?a=1').reply(200, simpleResponseBody); + + // new CallbackDecorator(httpTransport) + // .get(url) + // .query('a', 1) + // .asBody((err, body) => { + // assert.ifError(err); + // assert.equal(body, simpleResponseBody); + // done(); + // }); + // }); + + // it('supports multiple query strings', (done) => { + // nock.cleanAll(); + // api.get('/?a=1&b=2&c=3').reply(200, simpleResponseBody); + + // new CallbackDecorator(httpTransport) + // .get(url) + // .query({ + // a: 1, + // b: 2, + // c: 3 + // }) + // .asBody((err, body) => { + // assert.ifError(err); + // assert.equal(body, simpleResponseBody); + // done(); + // }); + // }); + // }); }); diff --git a/test/client.js b/test/client.js index 4a941ff..3b45fa4 100644 --- a/test/client.js +++ b/test/client.js @@ -72,10 +72,11 @@ describe('HttpTransportClient', () => { }); describe('.get', () => { - it('returns a response', async () => { + it.only('returns a response', async () => { const res = await HttpTransport.createClient() .get(url) .asResponse(); + console.log("🚀 ~ file: client.js:79 ~ it.only ~ res:", res) assert.equal(res.body, simpleResponseBody); }); From eddb7a9cbdbbbfcbf2c75c73aa2ecb0430f4f559 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 15 Aug 2023 16:59:16 +0100 Subject: [PATCH 02/69] get request working with node fetch --- lib/client.js | 4 +--- lib/transport/request.js | 7 +------ lib/transport/transport.js | 1 + test/client.js | 4 ++-- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/client.js b/lib/client.js index e0cabc2..3a77857 100644 --- a/lib/client.js +++ b/lib/client.js @@ -285,13 +285,11 @@ class HttpTransportClient { * */ async asResponse() { - console.log('asResponse') const currentContext = this._ctx; this._initContext(); const ctx = await retry(this._executeRequest, currentContext); - console.log('ctx: ', ctx) - return ctx.res; + return ctx.res.httpResponse; } _getPlugins(ctx) { diff --git a/lib/transport/request.js b/lib/transport/request.js index 9c27f01..6ada9de 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -23,7 +23,6 @@ class RequestTransport extends Transport { constructor(customRequest) { super(); this._request = customRequest || fetch; - console.log("🚀 ~ file: request.js:25 ~ RequestTransport ~ constructor ~ Request:", Request) } toOptions(ctx) { @@ -67,13 +66,9 @@ class RequestTransport extends Transport { makeRequest(ctx, opts) { console.log('opts', opts) - console.log('ctx: ', ctx) const url = ctx.req.getUrl(); const method = ctx.req.getMethod(); - console.log('method', method) - console.log('this._request', this._request) - opts.method = method - return this._request(url, opts); + return this._request(url, opts); // these options were originally passed to the request module, we need to translate it to node-fetch options } } diff --git a/lib/transport/transport.js b/lib/transport/transport.js index faa130f..9e8e657 100644 --- a/lib/transport/transport.js +++ b/lib/transport/transport.js @@ -13,6 +13,7 @@ class Transport { const opts = this.toOptions(ctx); return this.makeRequest(ctx, opts) .catch(this.onError(ctx)) + .then(res => res.json()) .then((res) => { ctx.res = this.toResponse(ctx, res); return ctx; diff --git a/test/client.js b/test/client.js index 3b45fa4..1f005d7 100644 --- a/test/client.js +++ b/test/client.js @@ -19,7 +19,7 @@ const host = 'http://www.example.com'; const api = nock(host); const path = '/'; -const simpleResponseBody = 'Illegitimi non carborundum'; +const simpleResponseBody = { 'blobby': 'Illegitimi non carborundum' }; const requestBody = { foo: 'bar' }; @@ -78,7 +78,7 @@ describe('HttpTransportClient', () => { .asResponse(); console.log("🚀 ~ file: client.js:79 ~ it.only ~ res:", res) - assert.equal(res.body, simpleResponseBody); + assert.deepEqual(res, simpleResponseBody); }); it('sets a default User-agent for every request', async () => { From 19e6f717a9ec82fb046669e8246774f6d731e98f Mon Sep 17 00:00:00 2001 From: Simon Tanner Date: Wed, 16 Aug 2023 13:33:24 +0100 Subject: [PATCH 03/69] chore: remove customrequest --- lib/transport/request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 6ada9de..f5b5c23 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -22,7 +22,7 @@ const REQUIRED_PROPERTIES = [ class RequestTransport extends Transport { constructor(customRequest) { super(); - this._request = customRequest || fetch; + this._request = fetch; } toOptions(ctx) { From 31701fc5b3e8bc14e63fd01ffb44e15f2b52d01c Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Wed, 16 Aug 2023 15:39:39 +0100 Subject: [PATCH 04/69] add https agent --- lib/transport/request.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index f5b5c23..34d3417 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -5,6 +5,7 @@ const _ = require('lodash'); const Transport = require('./transport'); const Request = require('request-promise-native'); const dns = require('dns'); +const https = require('node:https'); const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const REQUIRED_PROPERTIES = [ @@ -20,8 +21,11 @@ const REQUIRED_PROPERTIES = [ // } class RequestTransport extends Transport { - constructor(customRequest) { + constructor(defaultOptions) { super(); + if (defaultOptions) { + this._agent = new https.Agent(defaultOptions); + } this._request = fetch; } @@ -44,7 +48,9 @@ class RequestTransport extends Transport { } if (!_.isUndefined(req.time)) opts.time = req.time; - if (req.hasQueries()) opts.qs = req.getQueries(); + // if (req.hasQueries()) opts.qs = req.getQueries(); + if (req.hasQueries()) opts.searchParams = new URLSearchParams(req.getQueries()); + if (req.hasHeaders()) opts.headers = req.getHeaders(); const body = ctx.req.getBody(); if (body) { @@ -65,8 +71,12 @@ class RequestTransport extends Transport { } makeRequest(ctx, opts) { - console.log('opts', opts) + opts = { + ...opts, + agent: this._agent + }; const url = ctx.req.getUrl(); + if( opts.searchParams ) url += opts.searchParams; const method = ctx.req.getMethod(); return this._request(url, opts); // these options were originally passed to the request module, we need to translate it to node-fetch options } From 1bd71cc2f5bf954b3d0964960293df816c0b7a1f Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Mon, 21 Aug 2023 10:42:23 +0100 Subject: [PATCH 05/69] rename _request prop to _fetch --- lib/transport/request.js | 4 ++-- lib/transport/transport.js | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 34d3417..79cd05a 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -26,7 +26,7 @@ class RequestTransport extends Transport { if (defaultOptions) { this._agent = new https.Agent(defaultOptions); } - this._request = fetch; + this._fetch = fetch; } toOptions(ctx) { @@ -78,7 +78,7 @@ class RequestTransport extends Transport { const url = ctx.req.getUrl(); if( opts.searchParams ) url += opts.searchParams; const method = ctx.req.getMethod(); - return this._request(url, opts); // these options were originally passed to the request module, we need to translate it to node-fetch options + return this._fetch(url, opts); // these options were originally passed to the request module, we need to translate it to node-fetch options } } diff --git a/lib/transport/transport.js b/lib/transport/transport.js index 9e8e657..faa130f 100644 --- a/lib/transport/transport.js +++ b/lib/transport/transport.js @@ -13,7 +13,6 @@ class Transport { const opts = this.toOptions(ctx); return this.makeRequest(ctx, opts) .catch(this.onError(ctx)) - .then(res => res.json()) .then((res) => { ctx.res = this.toResponse(ctx, res); return ctx; From 3765d7d9b8dcd79992b8bb4c246bff1b9b11a127 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Mon, 21 Aug 2023 14:09:19 +0100 Subject: [PATCH 06/69] get cert opts --- lib/transport/request.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 79cd05a..4c41b9f 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -24,7 +24,7 @@ class RequestTransport extends Transport { constructor(defaultOptions) { super(); if (defaultOptions) { - this._agent = new https.Agent(defaultOptions); + this._agent = new https.Agent(defaultOptions.certOpts); } this._fetch = fetch; } @@ -62,6 +62,7 @@ class RequestTransport extends Transport { toResponse(ctx, from) { const to = ctx.res; + console.log({from}) REQUIRED_PROPERTIES.forEach((property) => { to[property] = from[property]; }); From d99dff613ffc9038ded6429072f4f36cf46e44c3 Mon Sep 17 00:00:00 2001 From: Richard Vaughan Date: Tue, 22 Aug 2023 11:00:09 +0100 Subject: [PATCH 07/69] chore: wip replicating json body behaviour from request in node-fetch --- lib/transport/request.js | 23 +++++++++++++++-------- lib/transport/transport.js | 22 +++++++++++++++------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 4c41b9f..15cc3fe 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -3,14 +3,14 @@ const _ = require('lodash'); // const promisifyAll = require('./promiseUtils').promisifyAll; const Transport = require('./transport'); -const Request = require('request-promise-native'); +//const Request = require('request-promise-native'); const dns = require('dns'); const https = require('node:https'); const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const REQUIRED_PROPERTIES = [ 'body', - 'elapsedTime', + 'elapsedTime', // get rid? 'url', 'statusCode', 'headers' @@ -51,27 +51,34 @@ class RequestTransport extends Transport { // if (req.hasQueries()) opts.qs = req.getQueries(); if (req.hasQueries()) opts.searchParams = new URLSearchParams(req.getQueries()); - if (req.hasHeaders()) opts.headers = req.getHeaders(); const body = ctx.req.getBody(); if (body) { - if (typeof body === 'object') opts.json = true; + if (typeof body === 'object') { + req.addHeader('Content-type','application/json'); + } opts.body = body; } + if (req.hasHeaders()) opts.headers = req.getHeaders(); + return opts; } - toResponse(ctx, from) { + async toResponse(ctx, from) { const to = ctx.res; - console.log({from}) + const contentType = from.headers.get('content-type') REQUIRED_PROPERTIES.forEach((property) => { to[property] = from[property]; }); + if (contentType === 'application/json; charset=utf-8') { //ignore charset bit? + to.body = await from.json(); + } + to.httpResponse = from; return to; } - makeRequest(ctx, opts) { + async makeRequest(ctx, opts) { opts = { ...opts, agent: this._agent @@ -79,7 +86,7 @@ class RequestTransport extends Transport { const url = ctx.req.getUrl(); if( opts.searchParams ) url += opts.searchParams; const method = ctx.req.getMethod(); - return this._fetch(url, opts); // these options were originally passed to the request module, we need to translate it to node-fetch options + return await this._fetch(url, opts); // these options were originally passed to the request module, we need to translate it to node-fetch options } } diff --git a/lib/transport/transport.js b/lib/transport/transport.js index faa130f..b1d4cfb 100644 --- a/lib/transport/transport.js +++ b/lib/transport/transport.js @@ -9,14 +9,22 @@ class Transport { return new Error(`Request failed for ${ctx.req.getMethod()} ${ctx.req.getUrl()}: ${err.message}`); } - execute(ctx) { + async execute(ctx) { const opts = this.toOptions(ctx); - return this.makeRequest(ctx, opts) - .catch(this.onError(ctx)) - .then((res) => { - ctx.res = this.toResponse(ctx, res); - return ctx; - }); + + try { + let res = await this.makeRequest(ctx, opts); + ctx.res = await this.toResponse(ctx, res); + } catch { + this.onError(ctx); + } + return ctx; + // return this.makeRequest(ctx, opts) + // .catch(this.onError(ctx)) + // .then((res) => { + // ctx.res = this.toResponse(ctx, res); + // return ctx; + // }); } onError(ctx) { From e8dffe531f845a0c114ae1d448c051ef33bdc357 Mon Sep 17 00:00:00 2001 From: Richard Vaughan Date: Tue, 22 Aug 2023 14:23:23 +0100 Subject: [PATCH 08/69] feat: convert response body to json/text accordingly --- lib/client.js | 2 +- lib/transport/request.js | 20 ++++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/client.js b/lib/client.js index 3a77857..de1afae 100644 --- a/lib/client.js +++ b/lib/client.js @@ -289,7 +289,7 @@ class HttpTransportClient { this._initContext(); const ctx = await retry(this._executeRequest, currentContext); - return ctx.res.httpResponse; + return ctx.res; } _getPlugins(ctx) { diff --git a/lib/transport/request.js b/lib/transport/request.js index 15cc3fe..4a19d5a 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -1,25 +1,19 @@ 'use strict'; const _ = require('lodash'); -// const promisifyAll = require('./promiseUtils').promisifyAll; const Transport = require('./transport'); -//const Request = require('request-promise-native'); const dns = require('dns'); const https = require('node:https'); const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const REQUIRED_PROPERTIES = [ 'body', - 'elapsedTime', // get rid? 'url', - 'statusCode', + 'status', + 'statusText', 'headers' ]; -// function toAsyncMethod(method) { -// return `${method.toLowerCase()}Async`; -// } - class RequestTransport extends Transport { constructor(defaultOptions) { super(); @@ -48,7 +42,6 @@ class RequestTransport extends Transport { } if (!_.isUndefined(req.time)) opts.time = req.time; - // if (req.hasQueries()) opts.qs = req.getQueries(); if (req.hasQueries()) opts.searchParams = new URLSearchParams(req.getQueries()); const body = ctx.req.getBody(); @@ -70,10 +63,13 @@ class RequestTransport extends Transport { to[property] = from[property]; }); - if (contentType === 'application/json; charset=utf-8') { //ignore charset bit? + // currently supports json and text formats only + if (contentType.includes("json")) { to.body = await from.json(); } - + else if (contentType.includes("text")) { + to.body = await from.text(); + } to.httpResponse = from; return to; } @@ -86,7 +82,7 @@ class RequestTransport extends Transport { const url = ctx.req.getUrl(); if( opts.searchParams ) url += opts.searchParams; const method = ctx.req.getMethod(); - return await this._fetch(url, opts); // these options were originally passed to the request module, we need to translate it to node-fetch options + return await this._fetch(url, opts); } } From 9b79c5cf8c2730b962155f72661c95d1a287c5d3 Mon Sep 17 00:00:00 2001 From: Richard Vaughan Date: Tue, 22 Aug 2023 16:57:48 +0100 Subject: [PATCH 09/69] feat: add AbortController signal opt --- lib/transport/request.js | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 4a19d5a..36746e1 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -75,14 +75,31 @@ class RequestTransport extends Transport { } async makeRequest(ctx, opts) { + const controller = new AbortController(); + let fetchedResponse; + opts = { ...opts, - agent: this._agent + agent: this._agent, + signal: controller.signal }; const url = ctx.req.getUrl(); if( opts.searchParams ) url += opts.searchParams; const method = ctx.req.getMethod(); - return await this._fetch(url, opts); + + const tOut = setTimeout(() => { + controller.abort(); + }, opts.timeout); + try { + fetchedResponse = await this._fetch(url, opts); + } catch (err) { + if (err instanceof AbortError) { + console.log('Request was aborted!'); + } + } finally { + clearTimeout(tOut); + } + return fetchedResponse } } From 644041ea8dfb9d9b825442b95ed2151d94cef2a7 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Wed, 23 Aug 2023 11:53:27 +0100 Subject: [PATCH 10/69] WIP handle errors correctly --- lib/transport/request.js | 28 +++++++++++++++------------- lib/transport/transport.js | 23 ++++++++++++++--------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 36746e1..727491d 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -58,48 +58,50 @@ class RequestTransport extends Transport { async toResponse(ctx, from) { const to = ctx.res; - const contentType = from.headers.get('content-type') + console.log('from', from) + const contentType = from.headers?.get('content-type'); REQUIRED_PROPERTIES.forEach((property) => { to[property] = from[property]; }); // currently supports json and text formats only - if (contentType.includes("json")) { + if (contentType?.includes("json")) { to.body = await from.json(); } - else if (contentType.includes("text")) { + else if (contentType?.includes("text")) { to.body = await from.text(); } + to.httpResponse = from; return to; } async makeRequest(ctx, opts) { const controller = new AbortController(); + const method = ctx.req.getMethod(); let fetchedResponse; opts = { ...opts, + method, agent: this._agent, signal: controller.signal }; + const url = ctx.req.getUrl(); - if( opts.searchParams ) url += opts.searchParams; - const method = ctx.req.getMethod(); + if ( opts.searchParams ) url += opts.searchParams; + + const timeout = setTimeout(() => { controller.abort(); }, opts.timeout); - const tOut = setTimeout(() => { - controller.abort(); - }, opts.timeout); try { fetchedResponse = await this._fetch(url, opts); } catch (err) { - if (err instanceof AbortError) { - console.log('Request was aborted!'); - } + throw new Error(err.message) } finally { - clearTimeout(tOut); + clearTimeout(timeout); } - return fetchedResponse + + return fetchedResponse; } } diff --git a/lib/transport/transport.js b/lib/transport/transport.js index b1d4cfb..61edec1 100644 --- a/lib/transport/transport.js +++ b/lib/transport/transport.js @@ -11,24 +11,29 @@ class Transport { async execute(ctx) { const opts = this.toOptions(ctx); + let from; try { - let res = await this.makeRequest(ctx, opts); - ctx.res = await this.toResponse(ctx, res); + from = await this.makeRequest(ctx, opts); } catch { - this.onError(ctx); + console.log('gets here') + from = this.onError(ctx); } + + ctx.res = await this.toResponse(ctx, from); return ctx; - // return this.makeRequest(ctx, opts) - // .catch(this.onError(ctx)) - // .then((res) => { - // ctx.res = this.toResponse(ctx, res); - // return ctx; - // }); + + // return this.makeRequest(ctx, opts) + // .catch(this.onError(ctx)) + // .then((res) => { + // ctx.res = this.toResponse(ctx, res); + // return ctx; + // }); } onError(ctx) { return (err) => { + console.log('does this ever get called') throw this.toError(err, ctx); }; } From e0976c7bc9717fb1f9bf8c5b48e913bd0ebad2f6 Mon Sep 17 00:00:00 2001 From: Richard Vaughan Date: Wed, 23 Aug 2023 12:22:13 +0100 Subject: [PATCH 11/69] feat: custom error message for timed out requests --- lib/transport/request.js | 8 +++++++- lib/transport/transport.js | 25 ++++--------------------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 727491d..0b4608d 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -96,7 +96,13 @@ class RequestTransport extends Transport { try { fetchedResponse = await this._fetch(url, opts); } catch (err) { - throw new Error(err.message) + + if (err.name === 'AbortError') { + throw new Error('Request timed out. Operation was aborted.'); + } + else { + throw new Error(err.message); + } } finally { clearTimeout(timeout); } diff --git a/lib/transport/transport.js b/lib/transport/transport.js index 61edec1..bffcf03 100644 --- a/lib/transport/transport.js +++ b/lib/transport/transport.js @@ -11,31 +11,14 @@ class Transport { async execute(ctx) { const opts = this.toOptions(ctx); - let from; try { - from = await this.makeRequest(ctx, opts); - } catch { - console.log('gets here') - from = this.onError(ctx); + let res = await this.makeRequest(ctx, opts); + ctx.res = await this.toResponse(ctx, res); + } catch (err) { + throw this.toError(err, ctx); } - - ctx.res = await this.toResponse(ctx, from); return ctx; - - // return this.makeRequest(ctx, opts) - // .catch(this.onError(ctx)) - // .then((res) => { - // ctx.res = this.toResponse(ctx, res); - // return ctx; - // }); - } - - onError(ctx) { - return (err) => { - console.log('does this ever get called') - throw this.toError(err, ctx); - }; } toOptions() { } From 20ac4b3bd1cbfa39c85f382c8c2d8da3d8f58274 Mon Sep 17 00:00:00 2001 From: Richard Vaughan Date: Wed, 23 Aug 2023 14:28:55 +0100 Subject: [PATCH 12/69] feat: remove elapsedTime from response --- index.d.ts | 2 -- lib/middleware/logger.js | 8 -------- lib/response.js | 5 +---- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/index.d.ts b/index.d.ts index 49187b2..0463177 100644 --- a/index.d.ts +++ b/index.d.ts @@ -23,7 +23,6 @@ export declare type ErrorObject = { export declare type JsonResponse = { body: string; - elapsedTime: number; url: string; headers: Object; statusCode: number; @@ -81,7 +80,6 @@ export declare class Request { export declare class Response { headers: Header[]; - elapsedTime: number; url: string; statusCode: number; body: Body; diff --git a/lib/middleware/logger.js b/lib/middleware/logger.js index d728559..d6e75b5 100644 --- a/lib/middleware/logger.js +++ b/lib/middleware/logger.js @@ -11,10 +11,6 @@ function isCriticalError(ctx) { return ctx.res.statusCode >= 500; } -function hasElapsedTime(ctx) { - return !_.isUndefined(_.get(ctx, 'res.elapsedTime')); -} - function getBaseMessage(ctx) { return `${ctx.req.getMethod()} ${ctx.req.getUrl()} ${ctx.res.statusCode}`; } @@ -23,8 +19,6 @@ function createRequestMessage(ctx) { const res = ctx.res; const message = getBaseMessage(ctx); - if (hasElapsedTime(ctx)) return `${message} ${res.elapsedTime} ms`; - return message; } @@ -33,8 +27,6 @@ function createRetryMessage(ctx) { const attempts = ctx.retryAttempts; const message = `Attempt ${attempts.length} ${getBaseMessage(ctx)}`; - if (hasElapsedTime(ctx)) return `${message} ${res.elapsedTime} ms`; - return message; } diff --git a/lib/response.js b/lib/response.js index 39f42f2..8102a41 100644 --- a/lib/response.js +++ b/lib/response.js @@ -6,14 +6,12 @@ const REQUIRED_PROPERTIES = [ 'url', 'body', 'statusCode', - 'headers', - 'elapsedTime' + 'headers' ]; class Response { constructor() { this.headers = {}; - this.elapsedTime = 0; this.url; this.statusCode; this.body; @@ -48,7 +46,6 @@ class Response { toJSON() { return { body: this.body, - elapsedTime: this.elapsedTime, url: this.url, headers: this.headers, statusCode: this.statusCode From 4c286cfc8c9eb9438d814eeb4b23deaedab9dd9c Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Wed, 23 Aug 2023 15:26:09 +0100 Subject: [PATCH 13/69] reads agent options from agentOpts --- lib/transport/request.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 0b4608d..a17fa6a 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -18,7 +18,7 @@ class RequestTransport extends Transport { constructor(defaultOptions) { super(); if (defaultOptions) { - this._agent = new https.Agent(defaultOptions.certOpts); + this._agent = new https.Agent(defaultOptions.agentOpts); } this._fetch = fetch; } @@ -58,7 +58,6 @@ class RequestTransport extends Transport { async toResponse(ctx, from) { const to = ctx.res; - console.log('from', from) const contentType = from.headers?.get('content-type'); REQUIRED_PROPERTIES.forEach((property) => { to[property] = from[property]; From 3ed11200735b90368780f3e110c238fcc1fc3d75 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Wed, 23 Aug 2023 16:00:26 +0100 Subject: [PATCH 14/69] WIP use http proxy agent --- lib/transport/request.js | 10 ++++++++-- package.json | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index a17fa6a..210204b 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -4,6 +4,7 @@ const _ = require('lodash'); const Transport = require('./transport'); const dns = require('dns'); const https = require('node:https'); +const HttpsProxyAgent = require('https-proxy-agent'); const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const REQUIRED_PROPERTIES = [ @@ -17,9 +18,14 @@ const REQUIRED_PROPERTIES = [ class RequestTransport extends Transport { constructor(defaultOptions) { super(); - if (defaultOptions) { + if (defaultOptions?.agentOpts?.proxy) { + console.log('proxyful') + this.agent = new HttpsProxyAgent(defaultOptions.agentOpts.proxy, defaultOptions.agentOpts); + } else if (defaultOptions?.agentOpts) { + console.log('no proxy') this._agent = new https.Agent(defaultOptions.agentOpts); - } + } + this._fetch = fetch; } diff --git a/package.json b/package.json index aca9774..a761167 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "dependencies": { "@types/request": "^2.47.1", "bluebird": "^3.5.0", + "https-proxy-agent": "^7.0.1", "koa-compose": "^4.0.0", "lodash": "^4.17.4", "node-fetch": "^3.3.2", From af4c98c2916215992ea90a623b58ac72bc60584d Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Thu, 24 Aug 2023 13:58:08 +0100 Subject: [PATCH 15/69] remove proxy agent stuff --- lib/transport/request.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 210204b..2354875 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -4,7 +4,6 @@ const _ = require('lodash'); const Transport = require('./transport'); const dns = require('dns'); const https = require('node:https'); -const HttpsProxyAgent = require('https-proxy-agent'); const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const REQUIRED_PROPERTIES = [ @@ -18,11 +17,7 @@ const REQUIRED_PROPERTIES = [ class RequestTransport extends Transport { constructor(defaultOptions) { super(); - if (defaultOptions?.agentOpts?.proxy) { - console.log('proxyful') - this.agent = new HttpsProxyAgent(defaultOptions.agentOpts.proxy, defaultOptions.agentOpts); - } else if (defaultOptions?.agentOpts) { - console.log('no proxy') + if (defaultOptions?.agentOpts) { this._agent = new https.Agent(defaultOptions.agentOpts); } From b904a2cb112294a558f3428f368f4ae04479afc6 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Thu, 24 Aug 2023 14:01:21 +0100 Subject: [PATCH 16/69] uninstall proxy agent --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index a761167..aca9774 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ "dependencies": { "@types/request": "^2.47.1", "bluebird": "^3.5.0", - "https-proxy-agent": "^7.0.1", "koa-compose": "^4.0.0", "lodash": "^4.17.4", "node-fetch": "^3.3.2", From 082b4f3fe6b2984e7a0727b041ecbd67903946bb Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Thu, 24 Aug 2023 15:22:43 +0100 Subject: [PATCH 17/69] remove unnecessary override of dns lookup --- lib/transport/request.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 2354875..c64864c 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -26,23 +26,12 @@ class RequestTransport extends Transport { toOptions(ctx) { const req = ctx.req; - const opts = Object.assign({ - time: true, - agentOptions: { - lookup: function(domain, options, cb) { - // Prevent Node from reordering A and AAAA records. - // See https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback - options.verbatim = true; - return dns.lookup(domain, options, cb); - } - } - }, ctx.opts); + const opts = ctx.opts; if (req.getTimeout() !== undefined) { opts.timeout = req.getTimeout(); } - if (!_.isUndefined(req.time)) opts.time = req.time; if (req.hasQueries()) opts.searchParams = new URLSearchParams(req.getQueries()); const body = ctx.req.getBody(); From cf4b233d2a1a4f2d22efdf8cc6120f6cd728bf3b Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 29 Aug 2023 11:29:03 +0100 Subject: [PATCH 18/69] get test working --- lib/transport/request.js | 8 ++++++-- test/client.js | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index c64864c..8d45078 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -22,11 +22,14 @@ class RequestTransport extends Transport { } this._fetch = fetch; + console.log('gets here') } toOptions(ctx) { const req = ctx.req; - const opts = ctx.opts; + const opts = ctx.opts || {}; + + console.log({opts}) if (req.getTimeout() !== undefined) { opts.timeout = req.getTimeout(); @@ -41,6 +44,7 @@ class RequestTransport extends Transport { } opts.body = body; } + if (req.hasHeaders()) opts.headers = req.getHeaders(); return opts; @@ -80,7 +84,7 @@ class RequestTransport extends Transport { const url = ctx.req.getUrl(); if ( opts.searchParams ) url += opts.searchParams; - const timeout = setTimeout(() => { controller.abort(); }, opts.timeout); + const timeout = opts.timeout && setTimeout(() => { controller.abort(); }, opts.timeout); try { fetchedResponse = await this._fetch(url, opts); diff --git a/test/client.js b/test/client.js index 1f005d7..4ce1f0e 100644 --- a/test/client.js +++ b/test/client.js @@ -76,9 +76,8 @@ describe('HttpTransportClient', () => { const res = await HttpTransport.createClient() .get(url) .asResponse(); - console.log("🚀 ~ file: client.js:79 ~ it.only ~ res:", res) - assert.deepEqual(res, simpleResponseBody); + assert.deepEqual(res.body, simpleResponseBody); }); it('sets a default User-agent for every request', async () => { From 2b6b2e58b8fb21153522a1ff5d7558afc12976bd Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 29 Aug 2023 12:22:53 +0100 Subject: [PATCH 19/69] get first retry test working --- lib/transport/request.js | 4 ---- test/client.js | 15 +++++---------- test/toError.js | 6 +++--- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 8d45078..b21de13 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -22,15 +22,12 @@ class RequestTransport extends Transport { } this._fetch = fetch; - console.log('gets here') } toOptions(ctx) { const req = ctx.req; const opts = ctx.opts || {}; - console.log({opts}) - if (req.getTimeout() !== undefined) { opts.timeout = req.getTimeout(); } @@ -89,7 +86,6 @@ class RequestTransport extends Transport { try { fetchedResponse = await this._fetch(url, opts); } catch (err) { - if (err.name === 'AbortError') { throw new Error('Request timed out. Operation was aborted.'); } diff --git a/test/client.js b/test/client.js index 4ce1f0e..d80dd37 100644 --- a/test/client.js +++ b/test/client.js @@ -39,7 +39,7 @@ function nockRetries(retry, opts) { nock.cleanAll(); api[httpMethod](path) .times(retry) - .reply(500); + .reply(500) api[httpMethod](path).reply(successCode); } @@ -72,7 +72,7 @@ describe('HttpTransportClient', () => { }); describe('.get', () => { - it.only('returns a response', async () => { + it('returns a response', async () => { const res = await HttpTransport.createClient() .get(url) .asResponse(); @@ -83,10 +83,9 @@ describe('HttpTransportClient', () => { it('sets a default User-agent for every request', async () => { nock.cleanAll(); - const HeaderValue = `${packageInfo.name}/${packageInfo.version}`; nock(host, { reqheaders: { - 'User-Agent': HeaderValue + 'User-Agent': `${packageInfo.name}/${packageInfo.version}` } }) .get(path) @@ -95,8 +94,6 @@ describe('HttpTransportClient', () => { const client = HttpTransport.createClient(); await client.get(url).asResponse(); - - return client.get(url).asResponse(); }); it('overrides the default User-agent for every request', async () => { @@ -116,8 +113,6 @@ describe('HttpTransportClient', () => { .createClient(); await client.get(url).asResponse(); - - return client.get(url).asResponse(); }); }); @@ -142,7 +137,7 @@ describe('HttpTransportClient', () => { }); describe('.retries', () => { - it('retries a given number of times for failed requests', async () => { + it.only('retries a given number of times for failed requests', async () => { nockRetries(2); const client = HttpTransport.createBuilder() @@ -154,7 +149,7 @@ describe('HttpTransportClient', () => { .retry(2) .asResponse(); - assert.equal(res.statusCode, 200); + assert.equal(res.status, 200); }); it('retries a given number of times for requests that timed out', async () => { diff --git a/test/toError.js b/test/toError.js index a32e3a3..5b36b17 100644 --- a/test/toError.js +++ b/test/toError.js @@ -4,9 +4,9 @@ function toError() { return async (ctx, next) => { await next(); - if (ctx.res.statusCode >= 400) { - const err = new Error('something bad happend.'); - err.statusCode = ctx.res.statusCode; + if (ctx.res.status >= 400) { + const err = new Error('something bad happened.'); + err.statusCode = ctx.res.status; err.headers = ctx.res.headers; throw err; } From cfb0707783b4ae3f59c146038ecd9564a03589ac Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 29 Aug 2023 15:20:44 +0100 Subject: [PATCH 20/69] fix more timeout tests --- test/client.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/client.js b/test/client.js index d80dd37..c866cb2 100644 --- a/test/client.js +++ b/test/client.js @@ -137,7 +137,7 @@ describe('HttpTransportClient', () => { }); describe('.retries', () => { - it.only('retries a given number of times for failed requests', async () => { + it('retries a given number of times for failed requests', async () => { nockRetries(2); const client = HttpTransport.createBuilder() @@ -161,14 +161,14 @@ describe('HttpTransportClient', () => { const res = await client .get(url) - .timeout(2000) + .timeout(500) .retry(2) .asResponse(); - assert.equal(res.statusCode, 200); + assert.equal(res.status, 200); }); - it('waits a minimum of 100ms between retries by default', async () => { + it.only('waits a minimum of 100ms between retries by default', async () => { nockRetries(1); const startTime = Date.now(); @@ -183,7 +183,7 @@ describe('HttpTransportClient', () => { const timeTaken = Date.now() - startTime; assert(timeTaken > 100); - assert.equal(res.statusCode, 200); + assert.equal(res.status, 200); }); it('disables retryDelay if retries if set to zero', async () => { From 657f2dfc882d3303ac1885cdb7f8dce24fcaf85c Mon Sep 17 00:00:00 2001 From: onlyonehas Date: Tue, 29 Aug 2023 16:02:53 +0100 Subject: [PATCH 21/69] chore: wip tests --- lib/client.js | 5 +++-- lib/transport/transport.js | 2 +- test/client.js | 28 ++++++++++++++-------------- test/toError.js | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/lib/client.js b/lib/client.js index de1afae..0097e86 100644 --- a/lib/client.js +++ b/lib/client.js @@ -267,6 +267,7 @@ class HttpTransportClient { */ async asBody() { const res = await this.asResponse(); + return res.body; } @@ -318,7 +319,7 @@ class HttpTransportClient { } function isCriticalError(err) { - if (err && err.statusCode < 500) { + if (err && err.status < 500) { return false; } return true; @@ -327,7 +328,7 @@ function isCriticalError(err) { function toRetry(err) { return { reason: err.message, - statusCode: err.statusCode + status: err.status }; } diff --git a/lib/transport/transport.js b/lib/transport/transport.js index bffcf03..c7f8c49 100644 --- a/lib/transport/transport.js +++ b/lib/transport/transport.js @@ -13,7 +13,7 @@ class Transport { const opts = this.toOptions(ctx); try { - let res = await this.makeRequest(ctx, opts); + const res = await this.makeRequest(ctx, opts); ctx.res = await this.toResponse(ctx, res); } catch (err) { throw this.toError(err, ctx); diff --git a/test/client.js b/test/client.js index c866cb2..488afb0 100644 --- a/test/client.js +++ b/test/client.js @@ -39,7 +39,7 @@ function nockRetries(retry, opts) { nock.cleanAll(); api[httpMethod](path) .times(retry) - .reply(500) + .reply(500); api[httpMethod](path).reply(successCode); } @@ -168,7 +168,7 @@ describe('HttpTransportClient', () => { assert.equal(res.status, 200); }); - it.only('waits a minimum of 100ms between retries by default', async () => { + it('waits a minimum of 100ms between retries by default', async () => { nockRetries(1); const startTime = Date.now(); @@ -201,7 +201,7 @@ describe('HttpTransportClient', () => { .retryDelay(10000) .asResponse(); } catch (e) { - return assert.equal(e.message, 'something bad happend.'); + return assert.equal(e.message, 'something bad happened.'); } assert.fail('Should have thrown'); @@ -224,7 +224,7 @@ describe('HttpTransportClient', () => { const timeTaken = Date.now() - startTime; assert(timeTaken > retryDelay); - assert.equal(res.statusCode, 200); + assert.equal(res.status, 200); }); it('does not retry 4XX errors', async () => { @@ -244,15 +244,15 @@ describe('HttpTransportClient', () => { .retry(1) .asResponse(); } catch (err) { - return assert.equal(err.statusCode, 400); + return assert.equal(err.status, 400); } assert.fail('Should have thrown'); }); }); describe('.post', () => { - it('makes a POST request', async () => { - api.post(path, requestBody).reply(201, responseBody); + it.only('makes a POST request', async () => { + const nock = api.post(path, requestBody).reply(201, responseBody); const body = await HttpTransport.createClient() .post(url, requestBody) @@ -270,7 +270,7 @@ describe('HttpTransportClient', () => { .post(url, requestBody) .asResponse(); } catch (err) { - return assert.equal(err.statusCode, 500); + return assert.equal(err.status, 500); } assert.fail('Should have thrown'); @@ -297,7 +297,7 @@ describe('HttpTransportClient', () => { .put(url, requestBody) .asResponse(); } catch (err) { - return assert.equal(err.statusCode, 500); + return assert.equal(err.status, 500); } assert.fail('Should have thrown'); @@ -319,7 +319,7 @@ describe('HttpTransportClient', () => { .delete(url) .asResponse(); } catch (err) { - return assert.equal(err.statusCode, 500); + return assert.equal(err.status, 500); } assert.fail('Should have thrown'); @@ -343,7 +343,7 @@ describe('HttpTransportClient', () => { .patch(url, requestBody) .asResponse(); } catch (err) { - return assert.equal(err.statusCode, 500); + return assert.equal(err.status, 500); } assert.fail('Should have thrown'); }); @@ -357,7 +357,7 @@ describe('HttpTransportClient', () => { .head(url) .asResponse(); - assert.strictEqual(res.statusCode, 200); + assert.strictEqual(res.status, 200); }); it('returns an error when the API returns a 5XX status code', async () => { @@ -369,7 +369,7 @@ describe('HttpTransportClient', () => { .head(url) .asResponse(); } catch (err) { - return assert.strictEqual(err.statusCode, 500); + return assert.strictEqual(err.status, 500); } assert.fail('Should have thrown'); }); @@ -397,7 +397,7 @@ describe('HttpTransportClient', () => { }) .asResponse(); - assert.equal(res.statusCode, 200); + assert.equal(res.status, 200); }); it('ignores an empty header object', async () => { diff --git a/test/toError.js b/test/toError.js index 5b36b17..33f857d 100644 --- a/test/toError.js +++ b/test/toError.js @@ -6,7 +6,7 @@ function toError() { if (ctx.res.status >= 400) { const err = new Error('something bad happened.'); - err.statusCode = ctx.res.status; + err.status = ctx.res.status; err.headers = ctx.res.headers; throw err; } From 7ffcb88bf41fea7f3ca2979abd98ea3a29879502 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 29 Aug 2023 17:00:54 +0100 Subject: [PATCH 22/69] WIP fix query string test --- lib/transport/request.js | 11 ++++++++--- test/client.js | 19 ++++++++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index b21de13..7ece730 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -38,8 +38,10 @@ class RequestTransport extends Transport { if (body) { if (typeof body === 'object') { req.addHeader('Content-type','application/json'); - } - opts.body = body; + opts.body = JSON.stringify(body); + } else { + opts.body = body; + } } if (req.hasHeaders()) opts.headers = req.getHeaders(); @@ -56,6 +58,7 @@ class RequestTransport extends Transport { // currently supports json and text formats only if (contentType?.includes("json")) { + console.log('gets here') to.body = await from.json(); } else if (contentType?.includes("text")) { @@ -78,8 +81,10 @@ class RequestTransport extends Transport { signal: controller.signal }; + + const url = ctx.req.getUrl(); - if ( opts.searchParams ) url += opts.searchParams; + //if ( opts.searchParams ) url = url + opts.searchParams.toString(); const timeout = opts.timeout && setTimeout(() => { controller.abort(); }, opts.timeout); diff --git a/test/client.js b/test/client.js index 488afb0..b6cac17 100644 --- a/test/client.js +++ b/test/client.js @@ -251,8 +251,8 @@ describe('HttpTransportClient', () => { }); describe('.post', () => { - it.only('makes a POST request', async () => { - const nock = api.post(path, requestBody).reply(201, responseBody); + it('makes a POST request', async () => { + const nock = api.post(path, requestBody).reply(201, responseBody, { 'content-type': 'application/json'}); const body = await HttpTransport.createClient() .post(url, requestBody) @@ -279,7 +279,7 @@ describe('HttpTransportClient', () => { describe('.put', () => { it('makes a PUT request with a JSON body', async () => { - api.put(path, requestBody).reply(201, responseBody); + api.put(path, requestBody).reply(201, responseBody, { 'content-type': 'application/json'}); const body = await HttpTransport.createClient() .put(url, requestBody) @@ -401,18 +401,23 @@ describe('HttpTransportClient', () => { }); it('ignores an empty header object', async () => { + nock.cleanAll(); + api.get(path).reply(200, simpleResponseBody, { 'content-type': 'application/json'}); + const res = await HttpTransport.createClient() .headers({}) .get(url) .asResponse(); - assert.equal(res.body, simpleResponseBody); + console.log('res.body', res.body) + console.log({simpleResponseBody}) + assert.deepEqual(res.body, simpleResponseBody); }); }); - describe('query strings', () => { - it('supports adding a query string', async () => { - api.get('/?a=1').reply(200, simpleResponseBody); + describe.only('query strings', () => { + it.only('supports adding a query string', async () => { + api.get('/?a=1').reply(200, simpleResponseBody, { 'content-type': 'application/json'}); const body = await HttpTransport.createClient() .get(url) From 1f34bf507a2d97bc267b3e9c6f37ea51898044ad Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Thu, 31 Aug 2023 14:00:48 +0100 Subject: [PATCH 23/69] client test file working --- lib/middleware/logger.js | 14 ++------- lib/transport/request.js | 23 ++++++--------- test/client.js | 62 +++++++++++++--------------------------- 3 files changed, 32 insertions(+), 67 deletions(-) diff --git a/lib/middleware/logger.js b/lib/middleware/logger.js index d6e75b5..416c5a5 100644 --- a/lib/middleware/logger.js +++ b/lib/middleware/logger.js @@ -8,22 +8,14 @@ function isRetry(ctx) { } function isCriticalError(ctx) { - return ctx.res.statusCode >= 500; + return ctx.res.status >= 500; } function getBaseMessage(ctx) { - return `${ctx.req.getMethod()} ${ctx.req.getUrl()} ${ctx.res.statusCode}`; -} - -function createRequestMessage(ctx) { - const res = ctx.res; - - const message = getBaseMessage(ctx); - return message; + return `${ctx.req.getMethod()} ${ctx.req.getUrl()} ${ctx.res.status}`; } function createRetryMessage(ctx) { - const res = ctx.res; const attempts = ctx.retryAttempts; const message = `Attempt ${attempts.length} ${getBaseMessage(ctx)}`; @@ -39,6 +31,6 @@ module.exports = (customLogger) => { if (isRetry(ctx) && isCriticalError(ctx)) { return logger.warn(createRetryMessage(ctx)); } - logger.info(createRequestMessage(ctx)); + logger.info(getBaseMessage(ctx)); }; }; diff --git a/lib/transport/request.js b/lib/transport/request.js index 7ece730..0913d38 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -57,14 +57,14 @@ class RequestTransport extends Transport { }); // currently supports json and text formats only - if (contentType?.includes("json")) { - console.log('gets here') - to.body = await from.json(); - } - else if (contentType?.includes("text")) { - to.body = await from.text(); + if (from.ok) { + if (contentType?.includes("json")) { + to.body = await from.json(); + } else if (contentType?.includes("text")) { + to.body = await from.text(); + } } - + to.httpResponse = from; return to; } @@ -81,18 +81,13 @@ class RequestTransport extends Transport { signal: controller.signal }; - - - const url = ctx.req.getUrl(); - //if ( opts.searchParams ) url = url + opts.searchParams.toString(); - const timeout = opts.timeout && setTimeout(() => { controller.abort(); }, opts.timeout); try { - fetchedResponse = await this._fetch(url, opts); + fetchedResponse = await this._fetch(ctx.req.getUrl(), opts); } catch (err) { if (err.name === 'AbortError') { - throw new Error('Request timed out. Operation was aborted.'); + throw new Error('ESOCKETTIMEDOUT'); } else { throw new Error(err.message); diff --git a/test/client.js b/test/client.js index b6cac17..b51f565 100644 --- a/test/client.js +++ b/test/client.js @@ -19,7 +19,7 @@ const host = 'http://www.example.com'; const api = nock(host); const path = '/'; -const simpleResponseBody = { 'blobby': 'Illegitimi non carborundum' }; +const simpleResponseBody = { 'blobbus': 'Illegitimi non carborundum' }; const requestBody = { foo: 'bar' }; @@ -28,7 +28,7 @@ const responseBody = requestBody; function toUpperCase() { return async (ctx, next) => { await next(); - ctx.res.body = ctx.res.body.toUpperCase(); + ctx.res.body.blobbus = ctx.res.body.blobbus.toUpperCase(); }; } @@ -40,7 +40,7 @@ function nockRetries(retry, opts) { api[httpMethod](path) .times(retry) .reply(500); - api[httpMethod](path).reply(successCode); + api[httpMethod](path).reply(successCode, simpleResponseBody); } function nockTimeouts(number, opts) { @@ -52,7 +52,7 @@ function nockTimeouts(number, opts) { .times(number) .delay(10000) .reply(200); - api[httpMethod](path).reply(successCode); + api[httpMethod](path).reply(successCode, simpleResponseBody); } describe('HttpTransportClient', () => { @@ -63,7 +63,7 @@ describe('HttpTransportClient', () => { .get(path) .reply(200, simpleResponseBody) .defaultReplyHeaders({ - 'Content-Type': 'text/html' + 'Content-Type': 'application/json' }); }); @@ -328,7 +328,7 @@ describe('HttpTransportClient', () => { describe('.patch', () => { it('makes a PATCH request', async () => { - api.patch(path).reply(204); + api.patch(path).reply(204, simpleResponseBody); await HttpTransport.createClient() .patch(url) .asResponse(); @@ -351,7 +351,7 @@ describe('HttpTransportClient', () => { describe('.head', () => { it('makes a HEAD request', async () => { - api.head(path).reply(200); + api.head(path).reply(200, simpleResponseBody); const res = await HttpTransport.createClient() .head(url) @@ -409,14 +409,12 @@ describe('HttpTransportClient', () => { .get(url) .asResponse(); - console.log('res.body', res.body) - console.log({simpleResponseBody}) assert.deepEqual(res.body, simpleResponseBody); }); }); - describe.only('query strings', () => { - it.only('supports adding a query string', async () => { + describe('query strings', () => { + it('supports adding a query string', async () => { api.get('/?a=1').reply(200, simpleResponseBody, { 'content-type': 'application/json'}); const body = await HttpTransport.createClient() @@ -424,12 +422,12 @@ describe('HttpTransportClient', () => { .query('a', 1) .asBody(); - assert.equal(body, simpleResponseBody); + assert.deepEqual(body, simpleResponseBody); }); it('supports multiple query strings', async () => { nock.cleanAll(); - api.get('/?a=1&b=2&c=3').reply(200, simpleResponseBody); + api.get('/?a=1&b=2&c=3').reply(200, simpleResponseBody, { 'content-type': 'application/json'}); const body = await HttpTransport.createClient() .get(url) @@ -440,7 +438,7 @@ describe('HttpTransportClient', () => { }) .asBody(); - assert.equal(body, simpleResponseBody); + assert.deepEqual(body, simpleResponseBody); }); it('ignores empty query objects', async () => { @@ -449,7 +447,7 @@ describe('HttpTransportClient', () => { .get(url) .asResponse(); - assert.equal(res.body, simpleResponseBody); + assert.deepEqual(res.body, simpleResponseBody); }); }); @@ -492,8 +490,8 @@ describe('HttpTransportClient', () => { .get(url) .asBody(); - assert.equal(upperCaseResponse, simpleResponseBody.toUpperCase()); - assert.equal(lowerCaseResponse, simpleResponseBody); + assert.equal(upperCaseResponse.blobbus, 'ILLEGITIMI NON CARBORUNDUM'); + assert.equal(lowerCaseResponse.blobbus, 'Illegitimi non carborundum'); }); it('executes global and per request plugins', async () => { @@ -631,7 +629,7 @@ describe('HttpTransportClient', () => { .asBody(); const message = stubbedLogger.info.getCall(0).args[0]; - assert.match(message, /GET http:\/\/www.example.com\/ 200 \d+ ms/); + assert.match(message, /GET http:\/\/www.example.com\/ 200/); }); it('uses default logger', async () => { @@ -647,31 +645,11 @@ describe('HttpTransportClient', () => { /*eslint no-console: ["error", { allow: ["info"] }] */ const message = console.info.getCall(0).args[0]; - assert.match(message, /GET http:\/\/www.example.com\/ 200 \d+ ms/); - }); - - it('doesnt log responseTime when undefined', async () => { - sandbox.stub(console, 'info'); - - const client = HttpTransport.createBuilder() - .use(log()) - .createClient(); - - await client - .use(setContextProperty({ - time: false - }, - 'opts' - )) - .get(url) - .asBody(); - - /*eslint no-console: ["error", { allow: ["info"] }] */ - const message = console.info.getCall(0).args[0]; - assert.match(message, /GET http:\/\/www.example.com\/ 200$/); + assert.match(message, /GET http:\/\/www.example.com\/ 200/); }); it('logs retry attempts as warnings when they return a critical error', async () => { + nock.cleanAll() sandbox.stub(console, 'info'); sandbox.stub(console, 'warn'); nockRetries(2); @@ -690,8 +668,8 @@ describe('HttpTransportClient', () => { sinon.assert.calledOnce(console.warn); const intial = console.info.getCall(0).args[0]; const attempt1 = console.warn.getCall(0).args[0]; - assert.match(intial, /GET http:\/\/www.example.com\/ 500 \d+ ms/); - assert.match(attempt1, /Attempt 1 GET http:\/\/www.example.com\/ 500 \d+ ms/); + assert.match(intial, /GET http:\/\/www.example.com\/ 500/); + assert.match(attempt1, /Attempt 1 GET http:\/\/www.example.com\/ 500/); }); }); }); From c86bb8d1506c5924b2aeb75bc363408fee587376 Mon Sep 17 00:00:00 2001 From: onlyonehas Date: Thu, 31 Aug 2023 14:56:06 +0100 Subject: [PATCH 24/69] chore: fixing linting + tests --- .eslintignore | 1 + lib/middleware/logger.js | 2 - lib/response.js | 2 - lib/transport/request.js | 2 +- package.json | 10 +- test/callbacks/client.js | 365 -------------------------------------- test/client.js | 14 +- test/response.js | 3 +- test/transport/request.js | 85 ++------- 9 files changed, 28 insertions(+), 456 deletions(-) delete mode 100644 test/callbacks/client.js diff --git a/.eslintignore b/.eslintignore index ba2a97b..40d51d6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ node_modules coverage +/lib/transport/request.js \ No newline at end of file diff --git a/lib/middleware/logger.js b/lib/middleware/logger.js index 416c5a5..302cfa1 100644 --- a/lib/middleware/logger.js +++ b/lib/middleware/logger.js @@ -1,7 +1,5 @@ 'use strict'; -const _ = require('lodash'); - function isRetry(ctx) { const attempts = ctx.retryAttempts || []; return attempts.length > 0; diff --git a/lib/response.js b/lib/response.js index 8102a41..d79f11d 100644 --- a/lib/response.js +++ b/lib/response.js @@ -1,7 +1,5 @@ 'use strict'; -const _ = require('lodash'); - const REQUIRED_PROPERTIES = [ 'url', 'body', diff --git a/lib/transport/request.js b/lib/transport/request.js index 0913d38..1fbbfac 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -2,8 +2,8 @@ const _ = require('lodash'); const Transport = require('./transport'); -const dns = require('dns'); const https = require('node:https'); +// eslint causing problems with import const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const REQUIRED_PROPERTIES = [ diff --git a/package.json b/package.json index aca9774..0315af5 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "test": "mocha", "jsdoc": "jsdoc -c ./docconfig/jsdoc.json", - "lint": "eslint ./src ./test", + "lint": "eslint ./lib ./test", "coverage": "nyc mocha && nyc report --reporter=html && nyc report --reporter=json-summary", "posttest": "npm run lint" }, @@ -38,9 +38,9 @@ "chai": "^3.5.0", "codeclimate-test-reporter": "^0.5.1", "coveralls": "^3.0.2", - "eslint": "^4.1.1", - "eslint-config-iplayer-es6": "^3.1.0", - "eslint-plugin-mocha": "^4.11.0", + "eslint": "^8.48.0", + "eslint-config-iplayer": "^8.0.0", + "eslint-plugin-mocha": "^10.1.0", "jsdoc": "^3.5.5", "mocha": "^7.2.0", "nock": "^11.9.1", @@ -62,7 +62,7 @@ "exit": true }, "eslintConfig": { - "extends": "iplayer-es6", + "extends": "iplayer", "parserOptions": { "ecmaVersion": 2017 }, diff --git a/test/callbacks/client.js b/test/callbacks/client.js deleted file mode 100644 index 83d4033..0000000 --- a/test/callbacks/client.js +++ /dev/null @@ -1,365 +0,0 @@ -'use strict'; - -const _ = require('lodash'); -const assert = require('chai').assert; -const nock = require('nock'); - -const HttpTransport = require('../..'); -const CallbackDecorator = require('../../lib/callbacks/decorator'); -const toError = require('../toError'); -const packageInfo = require('../../package'); - -const url = 'http://www.example.com/'; -const host = 'http://www.example.com'; -const api = nock(host); -const path = '/'; - -const simpleResponseBody = 'Illegitimi non carborundum'; -const requestBody = { - foo: 'bar' -}; -const responseBody = requestBody; - -function nockRetries(retry, opts) { - const httpMethod = _.get(opts, 'httpMethod') || 'get'; - const successCode = _.get(opts, 'successCode') || 200; - - nock.cleanAll(); - api[httpMethod](path) - .times(retry) - .reply(500); - api[httpMethod](path).reply(successCode); -} - -describe('CallbackDecorator', () => { - // let httpTransport; - - // beforeEach(() => { - // httpTransport = HttpTransport.createClient(); - // nock.disableNetConnect(); - // nock.cleanAll(); - // api.get(path).reply(200, simpleResponseBody); - // }); - - // it('decorates an instance of HttpTransport', (done) => { - // nock.cleanAll(); - - // nock(host) - // .get(path) - // .reply(200, 'the test passes'); - - // new CallbackDecorator(httpTransport) - // .get(url) - // .asResponse((err, res) => { - // assert.ifError(err); - // assert.equal(res.statusCode, 200); - // assert.equal(res.body, 'the test passes'); - // done(); - // }); - // }); - - // describe('.get', () => { - // it('returns a response', (done) => { - // new CallbackDecorator(httpTransport) - // .get(url) - // .asResponse((err, res) => { - // assert.ifError(err); - // assert.equal(res.body, simpleResponseBody); - // done(); - // }); - // }); - - // it('sets a default User-agent', (done) => { - // nock.cleanAll(); - - // const HeaderValue = `${packageInfo.name}/${packageInfo.version}`; - // nock(host, { - // reqheaders: { - // 'User-Agent': HeaderValue - // } - // }) - // .get(path) - // .reply(200, responseBody); - - // new CallbackDecorator(httpTransport) - // .get(url) - // .asResponse(() => { - // done(); - // }); - // }); - - // it('throws if a plugin is not a function', () => { - // assert.throws( - // () => { - // HttpTransport.createBuilder() - // .use('bad plugin') - // .asCallback(httpTransport); - // }, - // TypeError, - // 'Plugin is not a function' - // ); - // }); - // }); - - // describe('timeout', () => { - // it('sets the timeout', (done) => { - // nock.cleanAll(); - // api - // .get('/') - // .delay(1000) - // .reply(200, simpleResponseBody); - - // const client = new CallbackDecorator(httpTransport); - // client - // .get(url) - // .timeout(20) - // .asBody((err) => { - // assert.equal(err, 'Error: Request failed for GET http://www.example.com/: ESOCKETTIMEDOUT'); - // done(); - // }); - // }); - // }); - - // describe('.retries', () => { - // it('retries a given number of times for failed requests', (done) => { - // nockRetries(2); - // new CallbackDecorator(httpTransport) - // .use(toError()) - // .get(url) - // .retry(2) - // .asResponse((err, res) => { - // assert.ifError(err); - // assert.equal(res.statusCode, 200); - // done(); - // }); - // }); - - // it('waits a minimum of 100ms between retries by default', (done) => { - // nockRetries(1); - // const startTime = Date.now(); - - // const client = HttpTransport.createBuilder() - // .use(toError()) - // .asCallback() - // .createClient(); - - // client - // .get(url) - // .retry(2) - // .asResponse((err, res) => { - // assert.ifError(err); - // const timeTaken = Date.now() - startTime; - // assert(timeTaken > 100); - // assert.equal(res.statusCode, 200); - // done(); - // }); - // }); - - // it('overrides the minimum wait time between retries', (done) => { - // nockRetries(1); - // const retryDelay = 200; - // const startTime = Date.now(); - - // const client = HttpTransport.createBuilder() - // .use(toError()) - // .asCallback() - // .createClient(); - - // client - // .get(url) - // .retry(2) - // .retryDelay(retryDelay) - // .asResponse((err, res) => { - // assert.ifError(err); - // const timeTaken = Date.now() - startTime; - // assert(timeTaken > retryDelay, 'Responded faster than expected'); - // assert.equal(res.statusCode, 200); - // done(); - // }); - // }); - // }); - - // describe('.post', () => { - // it('makes a POST request', (done) => { - // api.post(path, requestBody).reply(201, responseBody); - - // new CallbackDecorator(httpTransport) - // .post(url, requestBody) - // .asBody((err, body) => { - // assert.ifError(err); - // assert.deepEqual(body, responseBody); - // done(); - // }); - // }); - - // it('returns an error when the API returns a 5XX status code', (done) => { - // api.post(path, requestBody).reply(500); - - // const client = HttpTransport.createBuilder(httpTransport) - // .use(toError()) - // .asCallback() - // .createClient(); - - // client.post(url, requestBody).asResponse((err) => { - // assert.ok(err); - // done(); - // }); - // }); - // }); - - // describe('.put', () => { - // it('makes a PUT request with a JSON body', (done) => { - // api.put(path, requestBody).reply(201, responseBody); - - // new CallbackDecorator(httpTransport) - // .put(url, requestBody) - // .asBody((err, body) => { - // assert.deepEqual(body, responseBody); - // done(); - // }); - // }); - - // it('returns an error when the API returns a 5XX status code', (done) => { - // api.put(path, requestBody).reply(500); - - // const client = HttpTransport.createBuilder(httpTransport) - // .use(toError()) - // .asCallback() - // .createClient(); - - // client.put(url, requestBody).asResponse((err) => { - // assert.ok(err); - // done(); - // }); - // }); - // }); - - // describe('.delete', () => { - // it('makes a DELETE request', (done) => { - // api.delete(path).reply(204); - // new CallbackDecorator(httpTransport) - // .delete(url) - // .asResponse(done); - // }); - - // it('returns an error when the API returns a 5XX status code', (done) => { - // api.delete(path).reply(500); - - // new CallbackDecorator(httpTransport) - // .delete(url) - // .asResponse((err) => { - // assert.ifError(err); - // done(); - // }); - // }); - // }); - - // describe('.patch', () => { - // it('makes a PATCH request', (done) => { - // api.patch(path).reply(204); - // new CallbackDecorator(httpTransport) - // .patch(url) - // .asResponse((err) => { - // assert.ifError(err); - // done(); - // }); - // }); - - // it('returns an error when the API returns a 5XX status code', (done) => { - // api.patch(path, requestBody).reply(500); - - // new CallbackDecorator(httpTransport) - // .patch(url, requestBody) - // .asResponse((err) => { - // assert.ifError(err); - // done(); - // }); - // }); - // }); - - // describe('.head', () => { - // it('makes a HEAD request', (done) => { - // api.head(path).reply(200); - - // new CallbackDecorator(httpTransport) - // .head(url) - // .asResponse((err, res) => { - // assert.ifError(err); - // assert.strictEqual(res.statusCode, 200); - // done(); - // }); - // }); - - // it('returns an error when the API returns a 5XX status code', (done) => { - // api.head(path).reply(500); - - // new CallbackDecorator(httpTransport) - // .head(url) - // .asResponse((err) => { - // assert.ifError(err); - // done(); - // }); - // }); - // }); - - // describe('.headers', () => { - // it('sends custom headers', (done) => { - // nock.cleanAll(); - - // const HeaderValue = `${packageInfo.name}/${packageInfo.version}`; - // nock(host, { - // reqheaders: { - // 'User-Agent': HeaderValue, - // foo: 'bar' - // } - // }) - // .get(path) - // .reply(200, responseBody); - - // new CallbackDecorator(httpTransport) - // .get(url) - // .headers({ - // 'User-Agent': HeaderValue, - // foo: 'bar' - // }) - // .asResponse((err, res) => { - // assert.ifError(err); - // assert.equal(res.statusCode, 200); - // done(); - // }); - // }); - // }); - - // describe('query strings', () => { - // it('supports adding a query string', (done) => { - // api.get('/?a=1').reply(200, simpleResponseBody); - - // new CallbackDecorator(httpTransport) - // .get(url) - // .query('a', 1) - // .asBody((err, body) => { - // assert.ifError(err); - // assert.equal(body, simpleResponseBody); - // done(); - // }); - // }); - - // it('supports multiple query strings', (done) => { - // nock.cleanAll(); - // api.get('/?a=1&b=2&c=3').reply(200, simpleResponseBody); - - // new CallbackDecorator(httpTransport) - // .get(url) - // .query({ - // a: 1, - // b: 2, - // c: 3 - // }) - // .asBody((err, body) => { - // assert.ifError(err); - // assert.equal(body, simpleResponseBody); - // done(); - // }); - // }); - // }); -}); diff --git a/test/client.js b/test/client.js index b51f565..9e1ccb6 100644 --- a/test/client.js +++ b/test/client.js @@ -19,7 +19,7 @@ const host = 'http://www.example.com'; const api = nock(host); const path = '/'; -const simpleResponseBody = { 'blobbus': 'Illegitimi non carborundum' }; +const simpleResponseBody = { blobbus: 'Illegitimi non carborundum' }; const requestBody = { foo: 'bar' }; @@ -252,7 +252,7 @@ describe('HttpTransportClient', () => { describe('.post', () => { it('makes a POST request', async () => { - const nock = api.post(path, requestBody).reply(201, responseBody, { 'content-type': 'application/json'}); + api.post(path, requestBody).reply(201, responseBody, { 'content-type': 'application/json' }); const body = await HttpTransport.createClient() .post(url, requestBody) @@ -279,7 +279,7 @@ describe('HttpTransportClient', () => { describe('.put', () => { it('makes a PUT request with a JSON body', async () => { - api.put(path, requestBody).reply(201, responseBody, { 'content-type': 'application/json'}); + api.put(path, requestBody).reply(201, responseBody, { 'content-type': 'application/json' }); const body = await HttpTransport.createClient() .put(url, requestBody) @@ -402,7 +402,7 @@ describe('HttpTransportClient', () => { it('ignores an empty header object', async () => { nock.cleanAll(); - api.get(path).reply(200, simpleResponseBody, { 'content-type': 'application/json'}); + api.get(path).reply(200, simpleResponseBody, { 'content-type': 'application/json' }); const res = await HttpTransport.createClient() .headers({}) @@ -415,7 +415,7 @@ describe('HttpTransportClient', () => { describe('query strings', () => { it('supports adding a query string', async () => { - api.get('/?a=1').reply(200, simpleResponseBody, { 'content-type': 'application/json'}); + api.get('/?a=1').reply(200, simpleResponseBody, { 'content-type': 'application/json' }); const body = await HttpTransport.createClient() .get(url) @@ -427,7 +427,7 @@ describe('HttpTransportClient', () => { it('supports multiple query strings', async () => { nock.cleanAll(); - api.get('/?a=1&b=2&c=3').reply(200, simpleResponseBody, { 'content-type': 'application/json'}); + api.get('/?a=1&b=2&c=3').reply(200, simpleResponseBody, { 'content-type': 'application/json' }); const body = await HttpTransport.createClient() .get(url) @@ -649,7 +649,7 @@ describe('HttpTransportClient', () => { }); it('logs retry attempts as warnings when they return a critical error', async () => { - nock.cleanAll() + nock.cleanAll(); sandbox.stub(console, 'info'); sandbox.stub(console, 'warn'); nockRetries(2); diff --git a/test/response.js b/test/response.js index 893c079..28e75ab 100644 --- a/test/response.js +++ b/test/response.js @@ -90,8 +90,7 @@ describe('Response', () => { const state = { url: 'https://www.example.com', body: 'body content', - statusCode: 200, - elapsedTime: 10 + statusCode: 200 }; const response = Response.create(state); diff --git a/test/transport/request.js b/test/transport/request.js index 313b38d..f0ca8e0 100644 --- a/test/transport/request.js +++ b/test/transport/request.js @@ -5,7 +5,6 @@ const nock = require('nock'); const context = require('../../lib/context'); const sinon = require('sinon'); const sandbox = sinon.sandbox.create(); -const dns = require('dns'); const RequestTransport = require('../../lib/transport/request'); @@ -18,6 +17,9 @@ const simpleResponseBody = 'Illegitimi non carborundum'; const requestBody = { foo: 'bar' }; +const header = { + 'Content-Type': 'text/html' +}; const responseBody = requestBody; function createContext(url, method) { @@ -32,7 +34,7 @@ describe('Request HTTP transport', () => { beforeEach(() => { nock.disableNetConnect(); nock.cleanAll(); - api.get(path).reply(200, simpleResponseBody); + api.get(path).reply(200, simpleResponseBody, header); }); afterEach(() => { @@ -47,7 +49,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.statusCode, 200); + assert.equal(ctx.res.status, 200); assert.equal(ctx.res.body, simpleResponseBody); }); }); @@ -60,7 +62,7 @@ describe('Request HTTP transport', () => { } }) .get(path) - .reply(200, simpleResponseBody); + .reply(200, simpleResponseBody, header); const ctx = createContext(url); ctx.req.addHeader('test', 'qui curat'); @@ -70,13 +72,13 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.statusCode, 200); + assert.equal(ctx.res.status, 200); assert.equal(ctx.res.body, simpleResponseBody); }); }); it('makes a GET request with query strings', () => { - api.get('/?a=1').reply(200, simpleResponseBody); + api.get('/?a=1').reply(200, simpleResponseBody, header); const ctx = createContext(url); ctx.req.addQuery('a', 1); @@ -86,7 +88,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.statusCode, 200); + assert.equal(ctx.res.status, 200); assert.equal(ctx.res.body, simpleResponseBody); }); }); @@ -128,7 +130,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.statusCode, 201); + assert.equal(ctx.res.status, 201); assert.deepEqual(ctx.res.body, responseBody); }); }); @@ -142,7 +144,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.statusCode, 201); + assert.equal(ctx.res.status, 201); assert.deepEqual(ctx.res.body, responseBody); }); }); @@ -156,7 +158,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.statusCode, 204); + assert.equal(ctx.res.status, 204); }); }); @@ -169,7 +171,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.statusCode, 204); + assert.equal(ctx.res.status, 204); }); }); @@ -209,66 +211,5 @@ describe('Request HTTP transport', () => { }) .catch(assert.ifError); }); - - it('enables timing request by default', () => { - nock.cleanAll(); - api.get('/').reply(200, simpleResponseBody); - - const ctx = createContext(url); - - return new RequestTransport() - .execute(ctx) - .then((ctx) => { - const timeTaken = ctx.res.elapsedTime; - assert.isNumber(timeTaken); - }) - .catch(assert.ifError); - }); - - it('override default request', () => { - nock.cleanAll(); - api - .get('/') - .delay(500) - .reply(200, simpleResponseBody); - - const res = { - body: simpleResponseBody, - elapsedTime: 10, - url: 'wheves', - statusCode: 200, - headers: [] - }; - - const ctx = createContext(url); - const customRequest = { - getAsync: sandbox.stub().returns(Promise.resolve(res)) - }; - - return new RequestTransport(customRequest) - .execute(ctx) - .then(() => { - sinon.assert.calledOnce(customRequest.getAsync); - }) - .catch(assert.ifError); - }); - - it('enables uses verbatim', () => { - nock.cleanAll(); - api.get('/').reply(200, simpleResponseBody); - - sinon.spy(dns, 'lookup'); - - const ctx = createContext(url); - - return new RequestTransport() - .execute(ctx) - .then((ctx) => { - ctx.res.httpResponse.request.agentOptions.lookup('www.example.com', {}, () => {}); - sinon.assert.calledWith(dns.lookup, 'www.example.com', {verbatim: true}); - }) - .catch(assert.ifError); - }); - }); }); From 42b7262855222f4c65c4f1f6b9bb9eea564053a2 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 10:35:18 +0100 Subject: [PATCH 25/69] adds elapsedTime to response --- lib/middleware/logger.js | 17 ++++++++++++++++- lib/response.js | 16 +++++++++++----- lib/transport/request.js | 5 ++++- package.json | 2 +- test/client.js | 8 ++++---- test/response.js | 6 +++--- test/transport/request.js | 21 ++++++++++++++++++--- 7 files changed, 57 insertions(+), 18 deletions(-) diff --git a/lib/middleware/logger.js b/lib/middleware/logger.js index 302cfa1..bfc35f5 100644 --- a/lib/middleware/logger.js +++ b/lib/middleware/logger.js @@ -9,14 +9,29 @@ function isCriticalError(ctx) { return ctx.res.status >= 500; } +function hasElapsedTime(ctx) { + return !!ctx.res?.elapsedTime; +} + function getBaseMessage(ctx) { return `${ctx.req.getMethod()} ${ctx.req.getUrl()} ${ctx.res.status}`; } +function createRequestMessage(ctx) { + const res = ctx.res; + + const message = getBaseMessage(ctx); + if (hasElapsedTime(ctx)) return `${message} ${res.elapsedTime} ms`; + + return message; +} + function createRetryMessage(ctx) { const attempts = ctx.retryAttempts; const message = `Attempt ${attempts.length} ${getBaseMessage(ctx)}`; + if (hasElapsedTime(ctx)) return `${message} ${ctx.res.elapsedTime} ms`; + return message; } @@ -29,6 +44,6 @@ module.exports = (customLogger) => { if (isRetry(ctx) && isCriticalError(ctx)) { return logger.warn(createRetryMessage(ctx)); } - logger.info(getBaseMessage(ctx)); + logger.info(createRequestMessage(ctx)); }; }; diff --git a/lib/response.js b/lib/response.js index d79f11d..1f01126 100644 --- a/lib/response.js +++ b/lib/response.js @@ -1,17 +1,21 @@ 'use strict'; const REQUIRED_PROPERTIES = [ - 'url', 'body', - 'statusCode', - 'headers' + 'url', + 'status', + 'statusText', + 'headers', + 'elapsedTime' ]; class Response { constructor() { this.headers = {}; this.url; - this.statusCode; + this.status; + this.statusText; + this.elapsedTime; this.body; this.httpResponse; } @@ -46,7 +50,9 @@ class Response { body: this.body, url: this.url, headers: this.headers, - statusCode: this.statusCode + status: this.status, + statusText: this.statusText, + elapsedTime: this.elapsedTime }; } diff --git a/lib/transport/request.js b/lib/transport/request.js index 1fbbfac..977e803 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -11,7 +11,8 @@ const REQUIRED_PROPERTIES = [ 'url', 'status', 'statusText', - 'headers' + 'headers', + 'elapsedTime' ]; class RequestTransport extends Transport { @@ -84,7 +85,9 @@ class RequestTransport extends Transport { const timeout = opts.timeout && setTimeout(() => { controller.abort(); }, opts.timeout); try { + const start = process.hrtime.bigint(); fetchedResponse = await this._fetch(ctx.req.getUrl(), opts); + fetchedResponse.elapsedTime = Math.round(Number(process.hrtime.bigint() - start) / 1e6); } catch (err) { if (err.name === 'AbortError') { throw new Error('ESOCKETTIMEDOUT'); diff --git a/package.json b/package.json index 0315af5..a28b758 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "eslintConfig": { "extends": "iplayer", "parserOptions": { - "ecmaVersion": 2017 + "ecmaVersion": "latest" }, "rules": { "space-before-function-paren": 0 diff --git a/test/client.js b/test/client.js index 9e1ccb6..5075b00 100644 --- a/test/client.js +++ b/test/client.js @@ -629,7 +629,7 @@ describe('HttpTransportClient', () => { .asBody(); const message = stubbedLogger.info.getCall(0).args[0]; - assert.match(message, /GET http:\/\/www.example.com\/ 200/); + assert.match(message, /GET http:\/\/www.example.com\/ 200 \d+ ms/); }); it('uses default logger', async () => { @@ -645,7 +645,7 @@ describe('HttpTransportClient', () => { /*eslint no-console: ["error", { allow: ["info"] }] */ const message = console.info.getCall(0).args[0]; - assert.match(message, /GET http:\/\/www.example.com\/ 200/); + assert.match(message, /GET http:\/\/www.example.com\/ 200 \d+ ms/); }); it('logs retry attempts as warnings when they return a critical error', async () => { @@ -668,8 +668,8 @@ describe('HttpTransportClient', () => { sinon.assert.calledOnce(console.warn); const intial = console.info.getCall(0).args[0]; const attempt1 = console.warn.getCall(0).args[0]; - assert.match(intial, /GET http:\/\/www.example.com\/ 500/); - assert.match(attempt1, /Attempt 1 GET http:\/\/www.example.com\/ 500/); + assert.match(intial, /GET http:\/\/www.example.com\/ 500 \d+ ms/); + assert.match(attempt1, /Attempt 1 GET http:\/\/www.example.com\/ 500 \d+ ms/); }); }); }); diff --git a/test/response.js b/test/response.js index 28e75ab..81d5e4b 100644 --- a/test/response.js +++ b/test/response.js @@ -8,12 +8,12 @@ describe('Response', () => { const properties = { url: 'https://www.example.com', body: 'body content', - statusCode: 200 + status: 200 }; const response = Response.create(properties); assert.equal(response.url, properties.url); - assert.equal(response.statusCode, properties.statusCode); + assert.equal(response.status, properties.status); assert.equal(response.body, properties.body); }); @@ -90,7 +90,7 @@ describe('Response', () => { const state = { url: 'https://www.example.com', body: 'body content', - statusCode: 200 + status: 200 }; const response = Response.create(state); diff --git a/test/transport/request.js b/test/transport/request.js index f0ca8e0..b8e7377 100644 --- a/test/transport/request.js +++ b/test/transport/request.js @@ -196,20 +196,35 @@ describe('Request HTTP transport', () => { }); }); - it('disables timing a request', () => { + it('enables timing request by default', () => { nock.cleanAll(); api.get('/').reply(200, simpleResponseBody); const ctx = createContext(url); - ctx.req.time = false; return new RequestTransport() .execute(ctx) .then((ctx) => { const timeTaken = ctx.res.elapsedTime; - assert.isNotNumber(timeTaken); + assert.isNumber(timeTaken); }) .catch(assert.ifError); }); + + // it('disables timing a request', () => { + // nock.cleanAll(); + // api.get('/').reply(200, simpleResponseBody); + + // const ctx = createContext(url); + // ctx.req.time = false; + + // return new RequestTransport() + // .execute(ctx) + // .then((ctx) => { + // const timeTaken = ctx.res.elapsedTime; + // assert.isNotNumber(timeTaken); + // }) + // .catch(assert.ifError); + // }); }); }); From 39eb8e272ed0688d8660da4b724c07b1ff8f715a Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 10:48:47 +0100 Subject: [PATCH 26/69] change status to statusCode on response --- lib/client.js | 4 ++-- lib/middleware/logger.js | 4 ++-- lib/response.js | 6 +++--- lib/transport/request.js | 4 +++- test/client.js | 34 +++++++++++++++++----------------- test/response.js | 6 +++--- test/toError.js | 4 ++-- test/transport/request.js | 30 +++++++----------------------- 8 files changed, 39 insertions(+), 53 deletions(-) diff --git a/lib/client.js b/lib/client.js index 0097e86..de5b266 100644 --- a/lib/client.js +++ b/lib/client.js @@ -319,7 +319,7 @@ class HttpTransportClient { } function isCriticalError(err) { - if (err && err.status < 500) { + if (err && err.statusCode < 500) { return false; } return true; @@ -328,7 +328,7 @@ function isCriticalError(err) { function toRetry(err) { return { reason: err.message, - status: err.status + statusCode: err.statusCode }; } diff --git a/lib/middleware/logger.js b/lib/middleware/logger.js index bfc35f5..1a2fed4 100644 --- a/lib/middleware/logger.js +++ b/lib/middleware/logger.js @@ -6,7 +6,7 @@ function isRetry(ctx) { } function isCriticalError(ctx) { - return ctx.res.status >= 500; + return ctx.res.statusCode >= 500; } function hasElapsedTime(ctx) { @@ -14,7 +14,7 @@ function hasElapsedTime(ctx) { } function getBaseMessage(ctx) { - return `${ctx.req.getMethod()} ${ctx.req.getUrl()} ${ctx.res.status}`; + return `${ctx.req.getMethod()} ${ctx.req.getUrl()} ${ctx.res.statusCode}`; } function createRequestMessage(ctx) { diff --git a/lib/response.js b/lib/response.js index 1f01126..bf94efc 100644 --- a/lib/response.js +++ b/lib/response.js @@ -3,7 +3,7 @@ const REQUIRED_PROPERTIES = [ 'body', 'url', - 'status', + 'statusCode', 'statusText', 'headers', 'elapsedTime' @@ -13,7 +13,7 @@ class Response { constructor() { this.headers = {}; this.url; - this.status; + this.statusCode; this.statusText; this.elapsedTime; this.body; @@ -50,7 +50,7 @@ class Response { body: this.body, url: this.url, headers: this.headers, - status: this.status, + statusCode: this.statusCode, statusText: this.statusText, elapsedTime: this.elapsedTime }; diff --git a/lib/transport/request.js b/lib/transport/request.js index 977e803..61c11c1 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -9,7 +9,7 @@ const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch const REQUIRED_PROPERTIES = [ 'body', 'url', - 'status', + 'statusCode', 'statusText', 'headers', 'elapsedTime' @@ -57,6 +57,8 @@ class RequestTransport extends Transport { to[property] = from[property]; }); + to.statusCode = from.status; + // currently supports json and text formats only if (from.ok) { if (contentType?.includes("json")) { diff --git a/test/client.js b/test/client.js index 5075b00..52df55a 100644 --- a/test/client.js +++ b/test/client.js @@ -149,7 +149,7 @@ describe('HttpTransportClient', () => { .retry(2) .asResponse(); - assert.equal(res.status, 200); + assert.equal(res.statusCode, 200); }); it('retries a given number of times for requests that timed out', async () => { @@ -165,7 +165,7 @@ describe('HttpTransportClient', () => { .retry(2) .asResponse(); - assert.equal(res.status, 200); + assert.equal(res.statusCode, 200); }); it('waits a minimum of 100ms between retries by default', async () => { @@ -183,7 +183,7 @@ describe('HttpTransportClient', () => { const timeTaken = Date.now() - startTime; assert(timeTaken > 100); - assert.equal(res.status, 200); + assert.equal(res.statusCode, 200); }); it('disables retryDelay if retries if set to zero', async () => { @@ -224,7 +224,7 @@ describe('HttpTransportClient', () => { const timeTaken = Date.now() - startTime; assert(timeTaken > retryDelay); - assert.equal(res.status, 200); + assert.equal(res.statusCode, 200); }); it('does not retry 4XX errors', async () => { @@ -244,7 +244,7 @@ describe('HttpTransportClient', () => { .retry(1) .asResponse(); } catch (err) { - return assert.equal(err.status, 400); + return assert.equal(err.statusCode, 400); } assert.fail('Should have thrown'); }); @@ -261,7 +261,7 @@ describe('HttpTransportClient', () => { assert.deepEqual(body, responseBody); }); - it('returns an error when the API returns a 5XX status code', async () => { + it('returns an error when the API returns a 5XX statusCode code', async () => { api.post(path, requestBody).reply(500); try { @@ -270,7 +270,7 @@ describe('HttpTransportClient', () => { .post(url, requestBody) .asResponse(); } catch (err) { - return assert.equal(err.status, 500); + return assert.equal(err.statusCode, 500); } assert.fail('Should have thrown'); @@ -288,7 +288,7 @@ describe('HttpTransportClient', () => { assert.deepEqual(body, responseBody); }); - it('returns an error when the API returns a 5XX status code', async () => { + it('returns an error when the API returns a 5XX statusCode code', async () => { api.put(path, requestBody).reply(500); try { @@ -297,7 +297,7 @@ describe('HttpTransportClient', () => { .put(url, requestBody) .asResponse(); } catch (err) { - return assert.equal(err.status, 500); + return assert.equal(err.statusCode, 500); } assert.fail('Should have thrown'); @@ -310,7 +310,7 @@ describe('HttpTransportClient', () => { return HttpTransport.createClient().delete(url); }); - it('returns an error when the API returns a 5XX status code', async () => { + it('returns an error when the API returns a 5XX statusCode code', async () => { api.delete(path).reply(500); try { @@ -319,7 +319,7 @@ describe('HttpTransportClient', () => { .delete(url) .asResponse(); } catch (err) { - return assert.equal(err.status, 500); + return assert.equal(err.statusCode, 500); } assert.fail('Should have thrown'); @@ -334,7 +334,7 @@ describe('HttpTransportClient', () => { .asResponse(); }); - it('returns an error when the API returns a 5XX status code', async () => { + it('returns an error when the API returns a 5XX statusCode code', async () => { api.patch(path, requestBody).reply(500); try { @@ -343,7 +343,7 @@ describe('HttpTransportClient', () => { .patch(url, requestBody) .asResponse(); } catch (err) { - return assert.equal(err.status, 500); + return assert.equal(err.statusCode, 500); } assert.fail('Should have thrown'); }); @@ -357,10 +357,10 @@ describe('HttpTransportClient', () => { .head(url) .asResponse(); - assert.strictEqual(res.status, 200); + assert.strictEqual(res.statusCode, 200); }); - it('returns an error when the API returns a 5XX status code', async () => { + it('returns an error when the API returns a 5XX statusCode code', async () => { api.head(path).reply(500); try { @@ -369,7 +369,7 @@ describe('HttpTransportClient', () => { .head(url) .asResponse(); } catch (err) { - return assert.strictEqual(err.status, 500); + return assert.strictEqual(err.statusCode, 500); } assert.fail('Should have thrown'); }); @@ -397,7 +397,7 @@ describe('HttpTransportClient', () => { }) .asResponse(); - assert.equal(res.status, 200); + assert.equal(res.statusCode, 200); }); it('ignores an empty header object', async () => { diff --git a/test/response.js b/test/response.js index 81d5e4b..28e75ab 100644 --- a/test/response.js +++ b/test/response.js @@ -8,12 +8,12 @@ describe('Response', () => { const properties = { url: 'https://www.example.com', body: 'body content', - status: 200 + statusCode: 200 }; const response = Response.create(properties); assert.equal(response.url, properties.url); - assert.equal(response.status, properties.status); + assert.equal(response.statusCode, properties.statusCode); assert.equal(response.body, properties.body); }); @@ -90,7 +90,7 @@ describe('Response', () => { const state = { url: 'https://www.example.com', body: 'body content', - status: 200 + statusCode: 200 }; const response = Response.create(state); diff --git a/test/toError.js b/test/toError.js index 33f857d..823464a 100644 --- a/test/toError.js +++ b/test/toError.js @@ -4,9 +4,9 @@ function toError() { return async (ctx, next) => { await next(); - if (ctx.res.status >= 400) { + if (ctx.res.statusCode >= 400) { const err = new Error('something bad happened.'); - err.status = ctx.res.status; + err.statusCode = ctx.res.statusCode; err.headers = ctx.res.headers; throw err; } diff --git a/test/transport/request.js b/test/transport/request.js index b8e7377..6b07610 100644 --- a/test/transport/request.js +++ b/test/transport/request.js @@ -49,7 +49,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.status, 200); + assert.equal(ctx.res.statusCode, 200); assert.equal(ctx.res.body, simpleResponseBody); }); }); @@ -72,7 +72,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.status, 200); + assert.equal(ctx.res.statusCode, 200); assert.equal(ctx.res.body, simpleResponseBody); }); }); @@ -88,7 +88,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.status, 200); + assert.equal(ctx.res.statusCode, 200); assert.equal(ctx.res.body, simpleResponseBody); }); }); @@ -130,7 +130,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.status, 201); + assert.equal(ctx.res.statusCode, 201); assert.deepEqual(ctx.res.body, responseBody); }); }); @@ -144,7 +144,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.status, 201); + assert.equal(ctx.res.statusCode, 201); assert.deepEqual(ctx.res.body, responseBody); }); }); @@ -158,7 +158,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.status, 204); + assert.equal(ctx.res.statusCode, 204); }); }); @@ -171,7 +171,7 @@ describe('Request HTTP transport', () => { .execute(ctx) .catch(assert.ifError) .then((ctx) => { - assert.equal(ctx.res.status, 204); + assert.equal(ctx.res.statusCode, 204); }); }); @@ -210,21 +210,5 @@ describe('Request HTTP transport', () => { }) .catch(assert.ifError); }); - - // it('disables timing a request', () => { - // nock.cleanAll(); - // api.get('/').reply(200, simpleResponseBody); - - // const ctx = createContext(url); - // ctx.req.time = false; - - // return new RequestTransport() - // .execute(ctx) - // .then((ctx) => { - // const timeTaken = ctx.res.elapsedTime; - // assert.isNotNumber(timeTaken); - // }) - // .catch(assert.ifError); - // }); }); }); From 1798742de55be9adfac371790016d49ef44b0164 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 11:03:36 +0100 Subject: [PATCH 27/69] fix linting errors in request --- .eslintignore | 3 +-- lib/transport/request.js | 20 +++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/.eslintignore b/.eslintignore index 40d51d6..3091757 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,2 @@ node_modules -coverage -/lib/transport/request.js \ No newline at end of file +coverage \ No newline at end of file diff --git a/lib/transport/request.js b/lib/transport/request.js index 61c11c1..383062a 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -1,10 +1,9 @@ 'use strict'; -const _ = require('lodash'); const Transport = require('./transport'); const https = require('node:https'); -// eslint causing problems with import -const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); +// eslint-disable-next-line func-style +const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args)); const REQUIRED_PROPERTIES = [ 'body', @@ -20,8 +19,8 @@ class RequestTransport extends Transport { super(); if (defaultOptions?.agentOpts) { this._agent = new https.Agent(defaultOptions.agentOpts); - } - + } + this._fetch = fetch; } @@ -38,7 +37,7 @@ class RequestTransport extends Transport { const body = ctx.req.getBody(); if (body) { if (typeof body === 'object') { - req.addHeader('Content-type','application/json'); + req.addHeader('Content-type', 'application/json'); opts.body = JSON.stringify(body); } else { opts.body = body; @@ -61,9 +60,9 @@ class RequestTransport extends Transport { // currently supports json and text formats only if (from.ok) { - if (contentType?.includes("json")) { + if (contentType?.includes('json')) { to.body = await from.json(); - } else if (contentType?.includes("text")) { + } else if (contentType?.includes('text')) { to.body = await from.text(); } } @@ -84,7 +83,7 @@ class RequestTransport extends Transport { signal: controller.signal }; - const timeout = opts.timeout && setTimeout(() => { controller.abort(); }, opts.timeout); + const timeout = opts.timeout && setTimeout(controller.abort, opts.timeout); try { const start = process.hrtime.bigint(); @@ -93,8 +92,7 @@ class RequestTransport extends Transport { } catch (err) { if (err.name === 'AbortError') { throw new Error('ESOCKETTIMEDOUT'); - } - else { + } else { throw new Error(err.message); } } finally { From 4b661b5f573ffbc2ac5b0b8cab61037bf200b2c3 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 11:05:43 +0100 Subject: [PATCH 28/69] whitespace --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 3091757..ba2a97b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,2 @@ node_modules -coverage \ No newline at end of file +coverage From 1547124386241be584a646ff191449defc7cf22a Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 11:07:49 +0100 Subject: [PATCH 29/69] add elapsedTime back to type def file --- index.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.d.ts b/index.d.ts index 0463177..49187b2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -23,6 +23,7 @@ export declare type ErrorObject = { export declare type JsonResponse = { body: string; + elapsedTime: number; url: string; headers: Object; statusCode: number; @@ -80,6 +81,7 @@ export declare class Request { export declare class Response { headers: Header[]; + elapsedTime: number; url: string; statusCode: number; body: Body; From 616f1bd558d66794a51503642b1321a440819f8e Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 11:08:48 +0100 Subject: [PATCH 30/69] whitespace --- lib/client.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/client.js b/lib/client.js index de5b266..de1afae 100644 --- a/lib/client.js +++ b/lib/client.js @@ -267,7 +267,6 @@ class HttpTransportClient { */ async asBody() { const res = await this.asResponse(); - return res.body; } From b76ee49d382e0ae803560d0b0c36b7baaa4deb43 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 11:13:14 +0100 Subject: [PATCH 31/69] tidy up response --- lib/middleware/logger.js | 4 +--- lib/response.js | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/middleware/logger.js b/lib/middleware/logger.js index 1a2fed4..16f3251 100644 --- a/lib/middleware/logger.js +++ b/lib/middleware/logger.js @@ -27,9 +27,7 @@ function createRequestMessage(ctx) { } function createRetryMessage(ctx) { - const attempts = ctx.retryAttempts; - - const message = `Attempt ${attempts.length} ${getBaseMessage(ctx)}`; + const message = `Attempt ${ctx.retryAttempts.length} ${getBaseMessage(ctx)}`; if (hasElapsedTime(ctx)) return `${message} ${ctx.res.elapsedTime} ms`; return message; diff --git a/lib/response.js b/lib/response.js index bf94efc..1f064b2 100644 --- a/lib/response.js +++ b/lib/response.js @@ -1,8 +1,8 @@ 'use strict'; const REQUIRED_PROPERTIES = [ - 'body', 'url', + 'body', 'statusCode', 'statusText', 'headers', @@ -12,10 +12,10 @@ const REQUIRED_PROPERTIES = [ class Response { constructor() { this.headers = {}; + this.elapsedTime = 0; this.url; this.statusCode; this.statusText; - this.elapsedTime; this.body; this.httpResponse; } @@ -48,11 +48,11 @@ class Response { toJSON() { return { body: this.body, + elapsedTime: this.elapsedTime, url: this.url, headers: this.headers, statusCode: this.statusCode, - statusText: this.statusText, - elapsedTime: this.elapsedTime + statusText: this.statusText }; } From ecc7acb517e0881ec7e6b75ba180636d7748d663 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 11:42:22 +0100 Subject: [PATCH 32/69] further tidy up --- lib/transport/request.js | 8 +++++--- test/response.js | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/transport/request.js b/lib/transport/request.js index 383062a..51cb78d 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -7,11 +7,11 @@ const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fet const REQUIRED_PROPERTIES = [ 'body', + 'elapsedTime', 'url', 'statusCode', 'statusText', - 'headers', - 'elapsedTime' + 'headers' ]; class RequestTransport extends Transport { @@ -83,7 +83,9 @@ class RequestTransport extends Transport { signal: controller.signal }; - const timeout = opts.timeout && setTimeout(controller.abort, opts.timeout); + const timeout = opts.timeout && setTimeout(() => { + controller.abort(); + }, opts.timeout); try { const start = process.hrtime.bigint(); diff --git a/test/response.js b/test/response.js index 28e75ab..893c079 100644 --- a/test/response.js +++ b/test/response.js @@ -90,7 +90,8 @@ describe('Response', () => { const state = { url: 'https://www.example.com', body: 'body content', - statusCode: 200 + statusCode: 200, + elapsedTime: 10 }; const response = Response.create(state); From b363f493fb1bbeec17dd98fcc7e0044a9e8a0b70 Mon Sep 17 00:00:00 2001 From: Simon Gregory Date: Tue, 5 Sep 2023 12:10:12 +0100 Subject: [PATCH 33/69] fix: correcting typos --- lib/builder.js | 2 +- lib/client.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/builder.js b/lib/builder.js index 361c239..d4ea943 100644 --- a/lib/builder.js +++ b/lib/builder.js @@ -26,7 +26,7 @@ class HttpTransportBuilder { /** * Sets a default user agent * - * @param {string} agent - user agant + * @param {string} agent - user agent * @return a HttpTransportBuilder instance * @example * const httpTransport = require('@bbc/http-transport'); diff --git a/lib/client.js b/lib/client.js index de1afae..19341e9 100644 --- a/lib/client.js +++ b/lib/client.js @@ -11,7 +11,7 @@ class HttpTransportClient { /** * Create a HttpTransport. * @param {Transport} transport - Transport instance. - * @param {object} defaults - default configutation + * @param {object} defaults - default configuration */ constructor(transport, defaults) { this._transport = transport; From 1ff8ac9cc62f64e50dd5f5cd54f902d63f840bd9 Mon Sep 17 00:00:00 2001 From: Simon Gregory Date: Tue, 5 Sep 2023 12:26:44 +0100 Subject: [PATCH 34/69] fix: correcting typos --- docs.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs.md b/docs.md index a2b5794..1dcd5c2 100644 --- a/docs.md +++ b/docs.md @@ -1,4 +1,4 @@ -# HttpTranport +# HttpTransport > A flexible, modular REST client built for ease-of-use and resilience @@ -32,7 +32,7 @@ PATCH, DELETE, HEAD are also supported. #### Query strings -Make a HTTP GET request specifiying query strings using `.query` +Make a HTTP GET request specifying query strings using `.query` Single query string ```js @@ -62,7 +62,7 @@ Multiple query strings: #### Headers -Make a HTTP GET request specifiying request headers using `.headers` +Make a HTTP GET request specifying request headers using `.headers` Add a single header: ```js @@ -176,7 +176,7 @@ Middleware are functions that can be executed with before and after a request. M * Terminate a request early e.g for caching purposes * Modify the response object e.g format the response body -Middlware can be executed **per request** using the `.use` method: +Middleware can be executed **per request** using the `.use` method: ```js const exampleMiddleware = require('exampleMiddleware'); @@ -193,7 +193,7 @@ Middlware can be executed **per request** using the `.use` method: } ``` -Middlware can also be executed **for every request** using the `.use` of the client builder. The client builder is created using the `createBuilder` method: +Middleware can also be executed **for every request** using the `.use` of the client builder. The client builder is created using the `createBuilder` method: ```js const exampleMiddleware = require('exampleMiddleware'); @@ -214,7 +214,7 @@ Middlware can also be executed **for every request** using the `.use` of the cli For writing middleware, see the [offical guide](https://github.com/koajs/koa/blob/master/docs/guide.md) -#### Offical HttpTransport middleware +#### Official HttpTransport middleware See [Caching](https://github.com/bbc/http-transport-cache) See [Collapsing](https://github.com/bbc/http-transport-request-collapse) From 6d256049aec1c2154f4e649b381c745270e708a5 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 16:12:14 +0100 Subject: [PATCH 35/69] removes all mention of the callbackifying stuff from code --- lib/builder.js | 21 +--------- lib/callbacks/decorator.js | 81 -------------------------------------- 2 files changed, 1 insertion(+), 101 deletions(-) delete mode 100644 lib/callbacks/decorator.js diff --git a/lib/builder.js b/lib/builder.js index d4ea943..65fe6bc 100644 --- a/lib/builder.js +++ b/lib/builder.js @@ -2,7 +2,6 @@ const _ = require('lodash'); -const CallbackDecorator = require('./callbacks/decorator'); const HttpTransportClient = require('./client'); function validatePlugin(plugin) { @@ -16,7 +15,6 @@ class HttpTransportBuilder { * @param {Transport} transport - Transport instance. */ constructor(transport) { - this._callback = false; this._transport = transport; this._defaults = { plugins: [] @@ -89,19 +87,6 @@ class HttpTransportBuilder { return this; } - /** - * Callbackify the client - * - * @return a HttpTransport instance supporting callbacks - * @example - * - * const client = httpTransport.asCallback().createClient(); - */ - asCallback() { - this._callback = true; - return this; - } - /** * Instantiates a HttpTransport * @@ -112,11 +97,7 @@ class HttpTransportBuilder { * const client = httpTransport.createClient(); */ createClient() { - const transportClient = new HttpTransportClient(this._transport, this._defaults); - if (this._callback) { - return new CallbackDecorator(transportClient); - } - return transportClient; + return new HttpTransportClient(this._transport, this._defaults); } } diff --git a/lib/callbacks/decorator.js b/lib/callbacks/decorator.js deleted file mode 100644 index fc4dcb2..0000000 --- a/lib/callbacks/decorator.js +++ /dev/null @@ -1,81 +0,0 @@ -'use strict'; - -const Bluebird = require('bluebird'); - -class CallbackDecorator { - constructor(delegate) { - this.delegate = delegate; - } - - use(plugin) { - this.delegate.use(plugin); - return this; - } - - timeout(ms) { - this.delegate.timeout(ms); - return this; - } - - retry(retries) { - this.delegate.retry(retries); - return this; - } - - retryDelay(delay) { - this.delegate.retryDelay(delay); - return this; - } - - get(url) { - this.delegate.get(url); - return this; - } - - post(url, body) { - this.delegate.post(url, body); - return this; - } - - put(url, body) { - this.delegate.put(url, body); - return this; - } - - head(url) { - this.delegate.head(url); - return this; - } - - headers() { - this.delegate.headers.apply(null, arguments); - return this; - } - - query() { - this.delegate.query.apply(null, arguments); - return this; - } - - delete(url) { - this.delegate.delete(url); - return this; - } - - patch(url, body) { - this.delegate.patch(url, body); - return this; - } - - asResponse(cb) { - const pending = this.delegate.asResponse(); - return Bluebird.resolve(pending).asCallback(cb); - } - - asBody(cb) { - const pending = this.delegate.asBody(); - return Bluebird.resolve(pending).asCallback(cb); - } -} - -module.exports = CallbackDecorator; From 8260c0b16e9f0bd0d7188bcc7f64e8d8c322c8e1 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Tue, 5 Sep 2023 16:16:19 +0100 Subject: [PATCH 36/69] removes statusText --- lib/response.js | 5 +---- lib/transport/request.js | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/response.js b/lib/response.js index 1f064b2..09be8c8 100644 --- a/lib/response.js +++ b/lib/response.js @@ -4,7 +4,6 @@ const REQUIRED_PROPERTIES = [ 'url', 'body', 'statusCode', - 'statusText', 'headers', 'elapsedTime' ]; @@ -15,7 +14,6 @@ class Response { this.elapsedTime = 0; this.url; this.statusCode; - this.statusText; this.body; this.httpResponse; } @@ -51,8 +49,7 @@ class Response { elapsedTime: this.elapsedTime, url: this.url, headers: this.headers, - statusCode: this.statusCode, - statusText: this.statusText + statusCode: this.statusCode }; } diff --git a/lib/transport/request.js b/lib/transport/request.js index 51cb78d..e5fe37d 100644 --- a/lib/transport/request.js +++ b/lib/transport/request.js @@ -10,7 +10,6 @@ const REQUIRED_PROPERTIES = [ 'elapsedTime', 'url', 'statusCode', - 'statusText', 'headers' ]; From 4dc1e4f594a907fddd8c864d2a6c49a2e2058b07 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Wed, 6 Sep 2023 11:56:46 +0100 Subject: [PATCH 37/69] remove bluebird dependency --- lib/transport/promiseUtils.js | 7 ------- package.json | 1 - 2 files changed, 8 deletions(-) delete mode 100644 lib/transport/promiseUtils.js diff --git a/lib/transport/promiseUtils.js b/lib/transport/promiseUtils.js deleted file mode 100644 index da21554..0000000 --- a/lib/transport/promiseUtils.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -const bluebird = require('bluebird'); - -module.exports.promisifyAll = (obj, opts) => { - return bluebird.promisifyAll(obj, opts); -}; diff --git a/package.json b/package.json index a28b758..f293e94 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ }, "dependencies": { "@types/request": "^2.47.1", - "bluebird": "^3.5.0", "koa-compose": "^4.0.0", "lodash": "^4.17.4", "node-fetch": "^3.3.2", From 50118cd4fd217722209ea8e3e86f0f6e9003aa14 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Wed, 6 Sep 2023 12:21:47 +0100 Subject: [PATCH 38/69] remove some uses of lodash --- lib/client.js | 3 +-- lib/context.js | 11 ++++------- test/client.js | 9 ++++----- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/client.js b/lib/client.js index 19341e9..377de88 100644 --- a/lib/client.js +++ b/lib/client.js @@ -1,6 +1,5 @@ 'use strict'; -const _ = require('lodash'); const compose = require('koa-compose'); const context = require('./context'); const rejectedPromise = require('./rejectedPromise'); @@ -15,7 +14,7 @@ class HttpTransportClient { */ constructor(transport, defaults) { this._transport = transport; - this._instancePlugins = _.get(defaults, 'plugins', []); + this._instancePlugins = defaults.plugins || []; this._defaults = defaults; this._initContext(); bind(this); diff --git a/lib/context.js b/lib/context.js index efaf15b..3909eea 100644 --- a/lib/context.js +++ b/lib/context.js @@ -1,7 +1,5 @@ 'use strict'; -const _ = require('lodash'); - const Request = require('./request'); const Response = require('./response'); const packageInfo = require('../package'); @@ -21,8 +19,7 @@ class Context { } get retryAttempts() { - if (_.isUndefined(this._retryAttempts)) return []; - return this._retryAttempts; + return this._retryAttempts || []; } set retryAttempts(retryAttempts) { @@ -38,9 +35,9 @@ class Context { } _applyDefaults(defaults) { - this.userAgent = _.get(defaults, 'ctx.userAgent', USER_AGENT); - this.retries = _.get(defaults, 'ctx.retries', RETRIES); - this.retryDelay = _.get(defaults, 'ctx.retryDelay', RETRY_DELAY); + this.userAgent = defaults.ctx?.userAgent || USER_AGENT; + this.retries = defaults.ctx?.retries || RETRIES; + this.retryDelay = defaults.ctx?.retryDelay || RETRY_DELAY; } static create(defaults) { diff --git a/test/client.js b/test/client.js index 52df55a..08831c8 100644 --- a/test/client.js +++ b/test/client.js @@ -1,6 +1,5 @@ 'use strict'; -const _ = require('lodash'); const assert = require('chai').assert; const nock = require('nock'); const sinon = require('sinon'); @@ -33,8 +32,8 @@ function toUpperCase() { } function nockRetries(retry, opts) { - const httpMethod = _.get(opts, 'httpMethod') || 'get'; - const successCode = _.get(opts, 'successCode') || 200; + const httpMethod = opts?.httpMethod || 'get'; + const successCode = opts?.successCode || 200; nock.cleanAll(); api[httpMethod](path) @@ -44,8 +43,8 @@ function nockRetries(retry, opts) { } function nockTimeouts(number, opts) { - const httpMethod = _.get(opts, 'httpMethod') || 'get'; - const successCode = _.get(opts, 'successCode') || 200; + const httpMethod = opts?.httpMethod || 'get'; + const successCode = opts?.successCode || 200; nock.cleanAll(); api[httpMethod](path) From 1fda64b2424047e1de9c58bb1bfab06bb0e08aa8 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Thu, 7 Sep 2023 14:44:23 +0100 Subject: [PATCH 39/69] renames RequestTransport to FetchTransport --- index.js | 4 ++-- lib/transport/{request.js => node-fetch.js} | 0 test/transport/request.js | 24 ++++++++++----------- 3 files changed, 14 insertions(+), 14 deletions(-) rename lib/transport/{request.js => node-fetch.js} (100%) diff --git a/index.js b/index.js index 83c9723..acc7f76 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,10 @@ 'use strict'; const HttpTransportBuilder = require('./lib/builder'); -const DefaultTransport = require('./lib/transport/request'); +const DefaultTransport = require('./lib/transport/node-fetch'); module.exports.defaultTransport = DefaultTransport; -module.exports.RequestTransport = DefaultTransport; +module.exports.FetchTransport = DefaultTransport; module.exports.builder = HttpTransportBuilder; module.exports.transport = require('./lib/transport/transport'); module.exports.context = require('./lib/context'); diff --git a/lib/transport/request.js b/lib/transport/node-fetch.js similarity index 100% rename from lib/transport/request.js rename to lib/transport/node-fetch.js diff --git a/test/transport/request.js b/test/transport/request.js index 6b07610..5346de4 100644 --- a/test/transport/request.js +++ b/test/transport/request.js @@ -6,7 +6,7 @@ const context = require('../../lib/context'); const sinon = require('sinon'); const sandbox = sinon.sandbox.create(); -const RequestTransport = require('../../lib/transport/request'); +const FetchTransport = require('../../lib/transport/node-fetch'); const url = 'http://www.example.com/'; const host = 'http://www.example.com'; @@ -44,7 +44,7 @@ describe('Request HTTP transport', () => { describe('.createRequest', () => { it('makes a GET request', () => { const ctx = createContext(url); - const request = new RequestTransport(); + const request = new FetchTransport(); return request .execute(ctx) .catch(assert.ifError) @@ -67,7 +67,7 @@ describe('Request HTTP transport', () => { const ctx = createContext(url); ctx.req.addHeader('test', 'qui curat'); - const request = new RequestTransport(); + const request = new FetchTransport(); return request .execute(ctx) .catch(assert.ifError) @@ -83,7 +83,7 @@ describe('Request HTTP transport', () => { const ctx = createContext(url); ctx.req.addQuery('a', 1); - const request = new RequestTransport(); + const request = new FetchTransport(); return request .execute(ctx) .catch(assert.ifError) @@ -96,7 +96,7 @@ describe('Request HTTP transport', () => { it('does not allow adding an empty query string', () => { const ctx = createContext(url); ctx.req.addQuery(); - const request = new RequestTransport(); + const request = new FetchTransport(); return request .execute(ctx) @@ -110,7 +110,7 @@ describe('Request HTTP transport', () => { it('does not allow adding an empty header', () => { const ctx = createContext(url); ctx.req.addHeader(); - const request = new RequestTransport(); + const request = new FetchTransport(); return request .execute(ctx) @@ -126,7 +126,7 @@ describe('Request HTTP transport', () => { const ctx = createContext(url, 'put'); ctx.req.body(requestBody); - return new RequestTransport() + return new FetchTransport() .execute(ctx) .catch(assert.ifError) .then((ctx) => { @@ -140,7 +140,7 @@ describe('Request HTTP transport', () => { const ctx = createContext(url, 'post'); ctx.req.body(requestBody); - return new RequestTransport() + return new FetchTransport() .execute(ctx) .catch(assert.ifError) .then((ctx) => { @@ -154,7 +154,7 @@ describe('Request HTTP transport', () => { const ctx = createContext(url, 'delete'); ctx.req.body(requestBody); - return new RequestTransport() + return new FetchTransport() .execute(ctx) .catch(assert.ifError) .then((ctx) => { @@ -167,7 +167,7 @@ describe('Request HTTP transport', () => { const ctx = createContext(url, 'patch'); ctx.req.body(requestBody); - return new RequestTransport() + return new FetchTransport() .execute(ctx) .catch(assert.ifError) .then((ctx) => { @@ -185,7 +185,7 @@ describe('Request HTTP transport', () => { const ctx = createContext(url); ctx.req.timeout(20); - return new RequestTransport() + return new FetchTransport() .execute(ctx) .then(() => { assert.fail('Expected request to timeout'); @@ -202,7 +202,7 @@ describe('Request HTTP transport', () => { const ctx = createContext(url); - return new RequestTransport() + return new FetchTransport() .execute(ctx) .then((ctx) => { const timeTaken = ctx.res.elapsedTime; From c010147c6d66e07a7d43f0809fc63753766469b4 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Fri, 8 Sep 2023 10:20:18 +0100 Subject: [PATCH 40/69] rename class --- lib/transport/node-fetch.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/transport/node-fetch.js b/lib/transport/node-fetch.js index e5fe37d..03d6937 100644 --- a/lib/transport/node-fetch.js +++ b/lib/transport/node-fetch.js @@ -13,7 +13,7 @@ const REQUIRED_PROPERTIES = [ 'headers' ]; -class RequestTransport extends Transport { +class FetchTransport extends Transport { constructor(defaultOptions) { super(); if (defaultOptions?.agentOpts) { @@ -104,4 +104,4 @@ class RequestTransport extends Transport { } } -module.exports = RequestTransport; +module.exports = FetchTransport; From b674b92da7a4285b667c5f2dca6d606cab991c10 Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Fri, 8 Sep 2023 15:26:09 +0100 Subject: [PATCH 41/69] enables setting timeout by default --- index.d.ts | 17 ++++++++++------- lib/transport/node-fetch.js | 12 ++++++------ test/transport/request.js | 24 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/index.d.ts b/index.d.ts index 49187b2..402d94f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,4 +1,5 @@ -import * as request from "request"; +import * as fetch from "node-fetch"; +import FetchTransport from "./lib/transport/node-fetch"; export declare function createBuilder( transport?: Transport @@ -85,7 +86,7 @@ export declare class Response { url: string; statusCode: number; body: Body; - httpResponse?: request.Response; + httpResponse?: fetch.Response; readonly length: number; static create(opts?: JsonResponse): Response; addHeader(key: string, value: string): Request; @@ -102,7 +103,6 @@ export declare class HttpTransportBuilder< use( fn: Plugin ): HttpTransportBuilder; - asCallback(): HttpTransportBuilder; createClient(): HttpTransportClient; } @@ -146,7 +146,7 @@ declare class Context { addPlugin(plugin: Plugin): Context; } -export declare class defaultTransport extends RequestTransport { +export declare class defaultTransport extends FetchTransport { constructor( params: request.RequestAPI< request.Request, @@ -155,8 +155,11 @@ export declare class defaultTransport extends RequestTransport { > ); } -export declare class RequestTransport extends Transport { +export declare class FetchTransport extends Transport { constructor( + agentOpts: { + + } params: request.RequestAPI< request.Request, request.CoreOptions, @@ -168,10 +171,10 @@ export declare class RequestTransport extends Transport { export declare class Transport { toError(err: ErrorObject, ctx: Context): Error; createError(err: ErrorObject, ctx: Context): Error; - execute(ctx: Context): Promise; + execute(ctx: Context): Promise; onError(ctx: Context): Function; toOptions(ctx: Context): RequestOptions; - toResponse(ctx: Context, from: request.Response): Response; + toResponse(ctx: Context, from: fetch.Response): Response; makeRequest(ctx: Context, opts: RequestOptions): Promise; } diff --git a/lib/transport/node-fetch.js b/lib/transport/node-fetch.js index 03d6937..2f6cde1 100644 --- a/lib/transport/node-fetch.js +++ b/lib/transport/node-fetch.js @@ -14,12 +14,14 @@ const REQUIRED_PROPERTIES = [ ]; class FetchTransport extends Transport { - constructor(defaultOptions) { + constructor(options) { super(); - if (defaultOptions?.agentOpts) { - this._agent = new https.Agent(defaultOptions.agentOpts); + if (options?.agentOpts) { + this._agent = new https.Agent(options.agentOpts); } + this.defaults = options?.defaults; + this._fetch = fetch; } @@ -27,9 +29,7 @@ class FetchTransport extends Transport { const req = ctx.req; const opts = ctx.opts || {}; - if (req.getTimeout() !== undefined) { - opts.timeout = req.getTimeout(); - } + opts.timeout = req.getTimeout() || this.defaults?.timeout; if (req.hasQueries()) opts.searchParams = new URLSearchParams(req.getQueries()); diff --git a/test/transport/request.js b/test/transport/request.js index 5346de4..cf4f94f 100644 --- a/test/transport/request.js +++ b/test/transport/request.js @@ -196,6 +196,30 @@ describe('Request HTTP transport', () => { }); }); + it('sets a default timeout', () => { + nock.cleanAll(); + api + .get('/') + .delay(500) + .reply(200, simpleResponseBody); + + const ctx = createContext(url); + + return new FetchTransport({ + defaults: { + timeout: 50 + } + }) + .execute(ctx) + .then(() => { + assert.fail('Expected request to timeout'); + }) + .catch((e) => { + assert.ok(e); + assert.equal(e.message, 'Request failed for get http://www.example.com/: ESOCKETTIMEDOUT'); + }); + }); + it('enables timing request by default', () => { nock.cleanAll(); api.get('/').reply(200, simpleResponseBody); From 06d96389403859ad0e65fffa3507c84c2f6e58dc Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Fri, 8 Sep 2023 16:05:27 +0100 Subject: [PATCH 42/69] updates type index --- index.d.ts | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/index.d.ts b/index.d.ts index 402d94f..1e7cd72 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,5 +1,6 @@ -import * as fetch from "node-fetch"; -import FetchTransport from "./lib/transport/node-fetch"; +import * as fetch from 'node-fetch'; +import * as https from 'node:https'; +import FetchTransport from './lib/transport/node-fetch'; export declare function createBuilder( transport?: Transport @@ -146,26 +147,19 @@ declare class Context { addPlugin(plugin: Plugin): Context; } +type TransportOptions = { + agentOpts: https.AgentOptions, + defaults?: { + timeout?: number + compress?: boolean + } +} + export declare class defaultTransport extends FetchTransport { - constructor( - params: request.RequestAPI< - request.Request, - request.CoreOptions, - request.RequiredUriUrl - > - ); + constructor(TransportOptions); } export declare class FetchTransport extends Transport { - constructor( - agentOpts: { - - } - params: request.RequestAPI< - request.Request, - request.CoreOptions, - request.RequiredUriUrl - > - ); + constructor(TransportOptions); } export declare class Transport { From 57fad88a6c8f1c4f7f6a3fb996571b2cb30c8a4c Mon Sep 17 00:00:00 2001 From: Jamie Reid Bower Date: Mon, 11 Sep 2023 11:41:09 +0100 Subject: [PATCH 43/69] passes through compress from default config, makes agentOpts optional of config --- index.d.ts | 10 +++++----- lib/transport/node-fetch.js | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/index.d.ts b/index.d.ts index 1e7cd72..24811ef 100644 --- a/index.d.ts +++ b/index.d.ts @@ -148,11 +148,11 @@ declare class Context { } type TransportOptions = { - agentOpts: https.AgentOptions, - defaults?: { - timeout?: number - compress?: boolean - } + agentOpts?: https.AgentOptions, + defaults?: { + timeout?: number + compress?: boolean + } } export declare class defaultTransport extends FetchTransport { diff --git a/lib/transport/node-fetch.js b/lib/transport/node-fetch.js index 2f6cde1..26064d9 100644 --- a/lib/transport/node-fetch.js +++ b/lib/transport/node-fetch.js @@ -30,6 +30,7 @@ class FetchTransport extends Transport { const opts = ctx.opts || {}; opts.timeout = req.getTimeout() || this.defaults?.timeout; + opts.compress = this.defaults?.compress; if (req.hasQueries()) opts.searchParams = new URLSearchParams(req.getQueries()); @@ -89,7 +90,7 @@ class FetchTransport extends Transport { try { const start = process.hrtime.bigint(); fetchedResponse = await this._fetch(ctx.req.getUrl(), opts); - fetchedResponse.elapsedTime = Math.round(Number(process.hrtime.bigint() - start) / 1e6); + fetchedResponse.elapsedTime = Math.round(Number(process.hrtime.bigint() - start) / 1e6); // nanoseconds to milliseconds } catch (err) { if (err.name === 'AbortError') { throw new Error('ESOCKETTIMEDOUT'); From 689c8dd45fd822e024571d456cdffe266a93903c Mon Sep 17 00:00:00 2001 From: Richard Vaughan Date: Mon, 11 Sep 2023 12:15:57 +0100 Subject: [PATCH 44/69] docs: update js docs with one section to todo --- docs.md | 43 +---------- docs/HttpTransportBuilder.html | 117 +++--------------------------- docs/HttpTransportClient.html | 36 +++++----- docs/builder.js.html | 27 ++----- docs/client.js.html | 9 ++- docs/index.html | 128 ++++++++++++++++++--------------- 6 files changed, 106 insertions(+), 254 deletions(-) diff --git a/docs.md b/docs.md index 1dcd5c2..3858cd7 100644 --- a/docs.md +++ b/docs.md @@ -108,7 +108,7 @@ Convert `Internal Server` responses (500) to errors: ``` `toError` is **only** required if the underlying client does not support HTTP error conversion. -The default transport is `request`, which does **not** convert errors. +The default transport is `node-fetch`, which does **not** convert errors. #### Retries @@ -227,46 +227,7 @@ See [Ratelimiting](https://github.com/bbc/http-transport-rate-limiter) See [xray](https://github.com/bbc/http-transport-xray) -#### Using alternative HTTP clients via transport decorators - -Make a HTTP GET request and supply an alternative HTTP transport via `.createClient` - -```js -const url = 'http://example.com/'; -const HttpTransport = require('@bbc/http-transport'); -const OtherTransport = require('some-other-transport'); - -const res = await HttpTransport.createClient(OtherTransport) - .get(url) - .asResponse(); - - if (res.statusCode === 200) { - console.log(res.body); - } -``` - -Make a HTTP GET request by configuring an alternative request instance and supplying it in RequestTransport transport via `.createClient` - -```js -const url = 'http://example.com/'; -const HttpTransport = require('@bbc/http-transport'); -const request = require('request'); - -const requestDefaults = { - headers: { - special: 'special value' - } -}; -const requestTransport = new HttpTransport.RequestTransport(request.defaults(requestDefaults)); - -const res = await HttpTransport.createClient(requestTransport); - .get(url) - .asResponse(); - - if (res.statusCode === 200) { - console.log(res.body); - } -``` +#### TODO: Client Setup #### Callback support HttpTransport does not support callbacks. However, to integrate with legacy code, use the [callback adapter](https://github.com/bbc/http-transport-callbacks) diff --git a/docs/HttpTransportBuilder.html b/docs/HttpTransportBuilder.html index 494ec72..706a119 100644 --- a/docs/HttpTransportBuilder.html +++ b/docs/HttpTransportBuilder.html @@ -23,7 +23,7 @@
@@ -66,7 +66,7 @@

n
Source:
@@ -205,105 +205,6 @@

Methods

-

asCallback()

- - - - - - -
- - -
Source:
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
-

Callbackify the client

-
- - - - - - - - - -
Example
- -
const client = httpTransport.asCallback().createClient();
- - - - - - - - - - - - - - - - -
Returns:
- - -
-

a HttpTransport instance supporting callbacks

-
- - - - - - - - - - -

createClient(fn)

@@ -316,7 +217,7 @@

createCli
Source:
@@ -464,7 +365,7 @@

retriesSource:
@@ -615,7 +516,7 @@

retryDelay<
Source:
@@ -766,7 +667,7 @@

useSource:
@@ -918,7 +819,7 @@

userAgentSource:
@@ -1020,7 +921,7 @@
Parameters:
-

user agant

+

user agent

@@ -1070,7 +971,7 @@
Returns:

- Documentation generated by JSDoc 3.5.5 on Thu Feb 07 2019 15:28:34 GMT+0000 (Greenwich Mean Time) using the docdash theme. + Documentation generated by JSDoc 3.6.11 on Mon Sep 11 2023 12:15:14 GMT+0100 (British Summer Time) using the docdash theme.
diff --git a/docs/HttpTransportClient.html b/docs/HttpTransportClient.html index 484fe96..72c6769 100644 --- a/docs/HttpTransportClient.html +++ b/docs/HttpTransportClient.html @@ -23,7 +23,7 @@
@@ -70,7 +70,7 @@

ne
Source:
@@ -187,7 +187,7 @@

Parameters:
-

default configutation

+

default configuration

@@ -244,7 +244,7 @@

(async) asBody<
Source:
@@ -349,7 +349,7 @@

(async) asR
Source:
@@ -454,7 +454,7 @@

deleteSource:
@@ -629,7 +629,7 @@

getSource:
@@ -781,7 +781,7 @@