From c21f3b3dc9386c0b51de36385c38890fa78854b0 Mon Sep 17 00:00:00 2001 From: Denis DelGrosso Date: Thu, 2 May 2024 18:28:24 +0000 Subject: [PATCH 1/6] feat: add request and response interceptors --- src/gaxios.ts | 67 ++++++++++++- src/index.ts | 1 + src/interceptor.ts | 104 ++++++++++++++++++++ test/test.getch.ts | 233 +++++++++++++++++++++++++++++++++++++++++++++ test/test.index.ts | 1 + 5 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 src/interceptor.ts diff --git a/src/gaxios.ts b/src/gaxios.ts index a0daeec5..e44a7b55 100644 --- a/src/gaxios.ts +++ b/src/gaxios.ts @@ -32,6 +32,7 @@ import { import {getRetryConfig} from './retry'; import {PassThrough, Stream, pipeline} from 'stream'; import {v4} from 'uuid'; +import {GaxiosInterceptorManager} from './interceptor'; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -63,6 +64,11 @@ function getHeader(options: GaxiosOptions, header: string): string | undefined { return undefined; } +enum GaxiosInterceptorType { + Request = 1, + Response, +} + export class Gaxios { protected agentCache = new Map< string | URL, @@ -74,12 +80,24 @@ export class Gaxios { */ defaults: GaxiosOptions; + /** + * Interceptors + */ + interceptors: { + request: GaxiosInterceptorManager; + response: GaxiosInterceptorManager; + }; + /** * The Gaxios class is responsible for making HTTP requests. * @param defaults The default set of options to be used for this instance. */ constructor(defaults?: GaxiosOptions) { this.defaults = defaults || {}; + this.interceptors = { + request: new GaxiosInterceptorManager(), + response: new GaxiosInterceptorManager(), + }; } /** @@ -88,7 +106,11 @@ export class Gaxios { */ async request(opts: GaxiosOptions = {}): GaxiosPromise { opts = await this.#prepareRequest(opts); - return this._request(opts); + opts = await this.#applyInterceptors(opts); + return this.#applyInterceptors( + this._request(opts), + GaxiosInterceptorType.Response + ); } private async _defaultAdapter( @@ -230,6 +252,49 @@ export class Gaxios { return true; } + /** + * Applies the interceptors. The request interceptors are applied after the + * call to prepareRequest is completed. The response interceptors are applied after the call + * to translateResponse. + * + * @param {T} optionsOrResponse The current set of options or the translated response. + * + * @returns {Promise} Promise that resolves to the set of options or response after interceptors are applied. + */ + async #applyInterceptors< + T extends + | GaxiosOptions + | GaxiosResponse + | Promise, + >( + optionsOrResponse: T, + type: GaxiosInterceptorType = GaxiosInterceptorType.Request + ): Promise { + let promiseChain = Promise.resolve(optionsOrResponse) as Promise; + + if (type === GaxiosInterceptorType.Request) { + for (const interceptor of this.interceptors.request) { + if (interceptor) { + promiseChain = promiseChain.then( + interceptor.resolved as unknown as (opts: T) => Promise, + interceptor.rejected + ) as Promise; + } + } + } else { + for (const interceptor of this.interceptors.response) { + if (interceptor) { + promiseChain = promiseChain.then( + interceptor.resolved as unknown as (resp: T) => Promise, + interceptor.rejected + ) as Promise; + } + } + } + + return promiseChain; + } + /** * Validates the options, merges them with defaults, and prepare request. * diff --git a/src/index.ts b/src/index.ts index 9d20638c..a18ddef3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,7 @@ export { RetryConfig, } from './common'; export {Gaxios, GaxiosOptions}; +export * from './interceptor'; /** * The default instance used when the `request` method is directly diff --git a/src/interceptor.ts b/src/interceptor.ts new file mode 100644 index 00000000..cf55edd1 --- /dev/null +++ b/src/interceptor.ts @@ -0,0 +1,104 @@ +// Copyright 2024 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import {GaxiosError, GaxiosOptions, GaxiosResponse} from './common'; + +/** + * Interceptors that can be run for requests or responses. These interceptors run asynchronously. + */ +export interface GaxiosInterceptor { + /** + * Function to be run when applying an interceptor. + * + * @param {T} configOrResponse The current configuration or response. + * @returns {Promise} Promise that resolves to the modified set of options or response. + */ + resolved?: (configOrResponse: T) => Promise; + /** + * Function to be run if the previous call to resolved throws / rejects or the request results in an invalid status + * as determined by the call to validateStatus. + * + * @param {GaxiosError} err The error thrown from the previously called resolved function. + */ + rejected?: (err: GaxiosError) => void; +} + +/** + * Class to manage collections of GaxiosInterceptors for both requests and responses. + */ +export class GaxiosInterceptorManager + implements + Iterator | null>, + Iterable | null> +{ + #interceptorQueue: Array | null>; + #index: number; + + constructor() { + this.#interceptorQueue = []; + this.#index = 0; + } + + [Symbol.iterator](): Iterator | null> { + return this; + } + + next(): IteratorResult< + GaxiosInterceptor | null, + GaxiosInterceptor | null + > { + const value = + this.#index < this.#interceptorQueue.length + ? this.#interceptorQueue[this.#index] + : undefined; + + return this.#index++ >= this.#interceptorQueue.length + ? ({ + done: true, + value, + } as IteratorReturnResult | null>) + : ({ + done: false, + value, + } as IteratorYieldResult | null>); + } + + /** + * Adds an interceptor to the queue. + * + * @param {GaxiosInterceptor} interceptor the interceptor to be added. + * + * @returns {number} an identifier that can be used to remove the interceptor. + */ + addInterceptor(interceptor: GaxiosInterceptor): number { + return this.#interceptorQueue.push(interceptor) - 1; + } + + /** + * Removes an interceptor from the queue. + * + * @param {number} id the previously id of the interceptor to remove. + */ + removeInterceptor(id: number) { + if (this.#interceptorQueue[id]) { + this.#interceptorQueue[id] = null; + } + } + + /** + * Removes all interceptors from the queue. + */ + removeAll() { + this.#interceptorQueue = []; + } +} diff --git a/test/test.getch.ts b/test/test.getch.ts index 353ac961..b25f91c0 100644 --- a/test/test.getch.ts +++ b/test/test.getch.ts @@ -1102,3 +1102,236 @@ describe('🍂 defaults & instances', () => { }); }); }); + +describe('interceptors', () => { + describe('request', () => { + it('should invoke a request interceptor when one is provided', async () => { + const scope = nock(url) + .matchHeader('hello', 'world') + .get('/') + .reply(200, {}); + const instance = new Gaxios(); + instance.interceptors.request.addInterceptor({ + resolved: config => { + config.headers = {hello: 'world'}; + return Promise.resolve(config); + }, + }); + await instance.request({url}); + scope.done(); + }); + + it('should not invoke a request interceptor after it is removed', async () => { + const scope = nock(url).persist().get('/').reply(200, {}); + const spyFunc = sinon.fake( + () => + Promise.resolve({ + url, + validateStatus: () => { + return true; + }, + }) as unknown as Promise + ); + const instance = new Gaxios(); + const id = instance.interceptors.request.addInterceptor({ + resolved: spyFunc, + }); + await instance.request({url}); + instance.interceptors.request.removeInterceptor(id); + await instance.request({url}); + scope.done(); + assert.strictEqual(spyFunc.callCount, 1); + }); + + it('should invoke multiple request interceptors in the order they were added', async () => { + const scope = nock(url) + .matchHeader('foo', 'bar') + .matchHeader('bar', 'baz') + .matchHeader('baz', 'buzz') + .get('/') + .reply(200, {}); + const instance = new Gaxios(); + instance.interceptors.request.addInterceptor({ + resolved: config => { + config.headers!['foo'] = 'bar'; + return Promise.resolve(config); + }, + }); + instance.interceptors.request.addInterceptor({ + resolved: config => { + assert.strictEqual(config.headers!['foo'], 'bar'); + config.headers!['bar'] = 'baz'; + return Promise.resolve(config); + }, + }); + instance.interceptors.request.addInterceptor({ + resolved: config => { + assert.strictEqual(config.headers!['foo'], 'bar'); + assert.strictEqual(config.headers!['bar'], 'baz'); + config.headers!['baz'] = 'buzz'; + return Promise.resolve(config); + }, + }); + await instance.request({url, headers: {}}); + scope.done(); + }); + + it('should not invoke a any request interceptors after they are removed', async () => { + const scope = nock(url).persist().get('/').reply(200, {}); + const spyFunc = sinon.fake( + () => + Promise.resolve({ + url, + validateStatus: () => { + return true; + }, + }) as unknown as Promise + ); + const instance = new Gaxios(); + instance.interceptors.request.addInterceptor({ + resolved: spyFunc, + }); + instance.interceptors.request.addInterceptor({ + resolved: spyFunc, + }); + instance.interceptors.request.addInterceptor({ + resolved: spyFunc, + }); + await instance.request({url}); + instance.interceptors.request.removeAll(); + await instance.request({url}); + scope.done(); + assert.strictEqual(spyFunc.callCount, 3); + }); + + it('should invoke the rejected function when a previous request interceptor rejects', async () => { + const instance = new Gaxios(); + instance.interceptors.request.addInterceptor({ + resolved: () => { + throw new Error('Something went wrong'); + }, + }); + instance.interceptors.request.addInterceptor({ + resolved: config => { + config.headers = {hello: 'world'}; + return Promise.resolve(config); + }, + rejected: err => { + assert.strictEqual(err.message, 'Something went wrong'); + }, + }); + // Because the options wind up being invalid the call will reject with a URL problem. + assert.rejects(instance.request({url})); + }); + }); + + describe('response', () => { + it('should invoke a response interceptor when one is provided', async () => { + const scope = nock(url).get('/').reply(200, {}); + const instance = new Gaxios(); + instance.interceptors.response.addInterceptor({ + resolved(response) { + response.headers['hello'] = 'world'; + return Promise.resolve(response); + }, + }); + const resp = await instance.request({url}); + scope.done(); + assert.strictEqual(resp.headers['hello'], 'world'); + }); + + it('should not invoke a response interceptor after it is removed', async () => { + const scope = nock(url).persist().get('/').reply(200, {}); + const spyFunc = sinon.fake( + () => + Promise.resolve({ + url, + validateStatus: () => { + return true; + }, + }) as unknown as Promise + ); + const instance = new Gaxios(); + const id = instance.interceptors.response.addInterceptor({ + resolved: spyFunc, + }); + await instance.request({url}); + instance.interceptors.response.removeInterceptor(id); + await instance.request({url}); + scope.done(); + assert.strictEqual(spyFunc.callCount, 1); + }); + + it('should invoke multiple response interceptors in the order they were added', async () => { + const scope = nock(url).get('/').reply(200, {}); + const instance = new Gaxios(); + instance.interceptors.response.addInterceptor({ + resolved: response => { + response.headers!['foo'] = 'bar'; + return Promise.resolve(response); + }, + }); + instance.interceptors.response.addInterceptor({ + resolved: response => { + assert.strictEqual(response.headers!['foo'], 'bar'); + response.headers!['bar'] = 'baz'; + return Promise.resolve(response); + }, + }); + instance.interceptors.response.addInterceptor({ + resolved: response => { + assert.strictEqual(response.headers!['foo'], 'bar'); + assert.strictEqual(response.headers!['bar'], 'baz'); + response.headers!['baz'] = 'buzz'; + return Promise.resolve(response); + }, + }); + const resp = await instance.request({url, headers: {}}); + scope.done(); + assert.strictEqual(resp.headers['foo'], 'bar'); + assert.strictEqual(resp.headers['bar'], 'baz'); + assert.strictEqual(resp.headers['baz'], 'buzz'); + }); + + it('should not invoke a any response interceptors after they are removed', async () => { + const scope = nock(url).persist().get('/').reply(200, {}); + const spyFunc = sinon.fake( + () => + Promise.resolve({ + url, + validateStatus: () => { + return true; + }, + }) as unknown as Promise + ); + const instance = new Gaxios(); + instance.interceptors.response.addInterceptor({ + resolved: spyFunc, + }); + instance.interceptors.response.addInterceptor({ + resolved: spyFunc, + }); + instance.interceptors.response.addInterceptor({ + resolved: spyFunc, + }); + await instance.request({url}); + instance.interceptors.response.removeAll(); + await instance.request({url}); + scope.done(); + assert.strictEqual(spyFunc.callCount, 3); + }); + + it('should invoke the rejected function when a request has an error', async () => { + const scope = nock(url).get('/').reply(404, {}); + const instance = new Gaxios(); + instance.interceptors.response.addInterceptor({ + rejected: err => { + assert.strictEqual(err.status, 404); + }, + }); + + await instance.request({url}); + scope.done(); + }); + }); +}); diff --git a/test/test.index.ts b/test/test.index.ts index ac22903f..de6eab4b 100644 --- a/test/test.index.ts +++ b/test/test.index.ts @@ -19,5 +19,6 @@ describe('📝 main exports', () => { it('should export all the types', () => { assert(main.Gaxios); assert(main.GaxiosError); + assert(main.GaxiosInterceptorManager); }); }); From 555c716c83525b1ee6429c544f7646bd92cd1878 Mon Sep 17 00:00:00 2001 From: Denis DelGrosso Date: Thu, 2 May 2024 18:38:38 +0000 Subject: [PATCH 2/6] pin compodoc due to unsupported node version in downstream dep --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 83071c29..d3dd73b9 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "license": "Apache-2.0", "devDependencies": { "@babel/plugin-proposal-private-methods": "^7.18.6", - "@compodoc/compodoc": "^1.1.9", + "@compodoc/compodoc": "1.1.21", "@types/cors": "^2.8.6", "@types/express": "^4.16.1", "@types/extend": "^3.0.1", From 1dbcf38341e9d789189058507d0b4ea0137fb8cf Mon Sep 17 00:00:00 2001 From: Denis DelGrosso Date: Fri, 3 May 2024 21:21:49 +0000 Subject: [PATCH 3/6] separate functions to apply request and response interceptors --- src/gaxios.ts | 83 +++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/src/gaxios.ts b/src/gaxios.ts index e44a7b55..88874aba 100644 --- a/src/gaxios.ts +++ b/src/gaxios.ts @@ -64,11 +64,6 @@ function getHeader(options: GaxiosOptions, header: string): string | undefined { return undefined; } -enum GaxiosInterceptorType { - Request = 1, - Response, -} - export class Gaxios { protected agentCache = new Map< string | URL, @@ -106,11 +101,8 @@ export class Gaxios { */ async request(opts: GaxiosOptions = {}): GaxiosPromise { opts = await this.#prepareRequest(opts); - opts = await this.#applyInterceptors(opts); - return this.#applyInterceptors( - this._request(opts), - GaxiosInterceptorType.Response - ); + opts = await this.#applyRequestInterceptors(opts); + return this.#applyResponseInterceptors(this._request(opts)); } private async _defaultAdapter( @@ -253,42 +245,49 @@ export class Gaxios { } /** - * Applies the interceptors. The request interceptors are applied after the - * call to prepareRequest is completed. The response interceptors are applied after the call - * to translateResponse. + * Applies the request interceptors. The request interceptors are applied after the + * call to prepareRequest is completed. * - * @param {T} optionsOrResponse The current set of options or the translated response. + * @param {GaxiosOptions} options The current set of options. * - * @returns {Promise} Promise that resolves to the set of options or response after interceptors are applied. + * @returns {Promise} Promise that resolves to the set of options or response after interceptors are applied. */ - async #applyInterceptors< - T extends - | GaxiosOptions - | GaxiosResponse - | Promise, - >( - optionsOrResponse: T, - type: GaxiosInterceptorType = GaxiosInterceptorType.Request - ): Promise { - let promiseChain = Promise.resolve(optionsOrResponse) as Promise; - - if (type === GaxiosInterceptorType.Request) { - for (const interceptor of this.interceptors.request) { - if (interceptor) { - promiseChain = promiseChain.then( - interceptor.resolved as unknown as (opts: T) => Promise, - interceptor.rejected - ) as Promise; - } + async #applyRequestInterceptors( + options: GaxiosOptions + ): Promise { + let promiseChain = Promise.resolve(options); + + for (const interceptor of this.interceptors.request) { + if (interceptor) { + promiseChain = promiseChain.then( + interceptor.resolved, + interceptor.rejected + ) as Promise; } - } else { - for (const interceptor of this.interceptors.response) { - if (interceptor) { - promiseChain = promiseChain.then( - interceptor.resolved as unknown as (resp: T) => Promise, - interceptor.rejected - ) as Promise; - } + } + + return promiseChain; + } + + /** + * Applies the response interceptors. The response interceptors are applied after the + * call to request is made. + * + * @param {GaxiosOptions} options The current set of options. + * + * @returns {Promise} Promise that resolves to the set of options or response after interceptors are applied. + */ + async #applyResponseInterceptors( + response: GaxiosResponse | Promise + ) { + let promiseChain = Promise.resolve(response); + + for (const interceptor of this.interceptors.response) { + if (interceptor) { + promiseChain = promiseChain.then( + interceptor.resolved, + interceptor.rejected + ) as Promise; } } From 14e4077e614e02e5426d997ef0d671c2574f326b Mon Sep 17 00:00:00 2001 From: Denis DelGrosso Date: Wed, 8 May 2024 15:02:32 +0000 Subject: [PATCH 4/6] Use map instead of array --- src/gaxios.ts | 4 ++-- src/interceptor.ts | 49 ++++++++++++---------------------------------- 2 files changed, 14 insertions(+), 39 deletions(-) diff --git a/src/gaxios.ts b/src/gaxios.ts index 88874aba..266e9fdc 100644 --- a/src/gaxios.ts +++ b/src/gaxios.ts @@ -257,7 +257,7 @@ export class Gaxios { ): Promise { let promiseChain = Promise.resolve(options); - for (const interceptor of this.interceptors.request) { + for (const interceptor of this.interceptors.request.interceptorMap.values()) { if (interceptor) { promiseChain = promiseChain.then( interceptor.resolved, @@ -282,7 +282,7 @@ export class Gaxios { ) { let promiseChain = Promise.resolve(response); - for (const interceptor of this.interceptors.response) { + for (const interceptor of this.interceptors.response.interceptorMap.values()) { if (interceptor) { promiseChain = promiseChain.then( interceptor.resolved, diff --git a/src/interceptor.ts b/src/interceptor.ts index cf55edd1..9ac6656c 100644 --- a/src/interceptor.ts +++ b/src/interceptor.ts @@ -36,41 +36,13 @@ export interface GaxiosInterceptor { /** * Class to manage collections of GaxiosInterceptors for both requests and responses. */ -export class GaxiosInterceptorManager - implements - Iterator | null>, - Iterable | null> -{ - #interceptorQueue: Array | null>; - #index: number; +export class GaxiosInterceptorManager< + T extends GaxiosOptions | GaxiosResponse, +> { + interceptorMap: Map | null>; constructor() { - this.#interceptorQueue = []; - this.#index = 0; - } - - [Symbol.iterator](): Iterator | null> { - return this; - } - - next(): IteratorResult< - GaxiosInterceptor | null, - GaxiosInterceptor | null - > { - const value = - this.#index < this.#interceptorQueue.length - ? this.#interceptorQueue[this.#index] - : undefined; - - return this.#index++ >= this.#interceptorQueue.length - ? ({ - done: true, - value, - } as IteratorReturnResult | null>) - : ({ - done: false, - value, - } as IteratorYieldResult | null>); + this.interceptorMap = new Map>(); } /** @@ -81,7 +53,10 @@ export class GaxiosInterceptorManager * @returns {number} an identifier that can be used to remove the interceptor. */ addInterceptor(interceptor: GaxiosInterceptor): number { - return this.#interceptorQueue.push(interceptor) - 1; + const index = this.interceptorMap.size; + this.interceptorMap.set(index, interceptor); + + return index; } /** @@ -90,8 +65,8 @@ export class GaxiosInterceptorManager * @param {number} id the previously id of the interceptor to remove. */ removeInterceptor(id: number) { - if (this.#interceptorQueue[id]) { - this.#interceptorQueue[id] = null; + if (this.interceptorMap.has(id)) { + this.interceptorMap.set(id, null); } } @@ -99,6 +74,6 @@ export class GaxiosInterceptorManager * Removes all interceptors from the queue. */ removeAll() { - this.#interceptorQueue = []; + this.interceptorMap.clear(); } } From a7a2ebf0c79e6c4c18065bfa16ac2cf136cea30e Mon Sep 17 00:00:00 2001 From: Denis DelGrosso Date: Wed, 8 May 2024 15:04:16 +0000 Subject: [PATCH 5/6] update docs --- src/interceptor.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/interceptor.ts b/src/interceptor.ts index 9ac6656c..7d30e6b9 100644 --- a/src/interceptor.ts +++ b/src/interceptor.ts @@ -46,7 +46,7 @@ export class GaxiosInterceptorManager< } /** - * Adds an interceptor to the queue. + * Adds an interceptor. * * @param {GaxiosInterceptor} interceptor the interceptor to be added. * @@ -60,7 +60,7 @@ export class GaxiosInterceptorManager< } /** - * Removes an interceptor from the queue. + * Removes an interceptor. * * @param {number} id the previously id of the interceptor to remove. */ @@ -71,7 +71,7 @@ export class GaxiosInterceptorManager< } /** - * Removes all interceptors from the queue. + * Removes all interceptors. */ removeAll() { this.interceptorMap.clear(); From 09bd5387df04d80836c8b530f0d6b87520f99e94 Mon Sep 17 00:00:00 2001 From: Denis DelGrosso Date: Tue, 14 May 2024 21:39:42 +0000 Subject: [PATCH 6/6] use set instead of map --- src/gaxios.ts | 4 ++-- src/interceptor.ts | 40 +---------------------------------- test/test.getch.ts | 52 ++++++++++++++++++++++------------------------ 3 files changed, 28 insertions(+), 68 deletions(-) diff --git a/src/gaxios.ts b/src/gaxios.ts index 266e9fdc..987644df 100644 --- a/src/gaxios.ts +++ b/src/gaxios.ts @@ -257,7 +257,7 @@ export class Gaxios { ): Promise { let promiseChain = Promise.resolve(options); - for (const interceptor of this.interceptors.request.interceptorMap.values()) { + for (const interceptor of this.interceptors.request.values()) { if (interceptor) { promiseChain = promiseChain.then( interceptor.resolved, @@ -282,7 +282,7 @@ export class Gaxios { ) { let promiseChain = Promise.resolve(response); - for (const interceptor of this.interceptors.response.interceptorMap.values()) { + for (const interceptor of this.interceptors.response.values()) { if (interceptor) { promiseChain = promiseChain.then( interceptor.resolved, diff --git a/src/interceptor.ts b/src/interceptor.ts index 7d30e6b9..d52aacbb 100644 --- a/src/interceptor.ts +++ b/src/interceptor.ts @@ -38,42 +38,4 @@ export interface GaxiosInterceptor { */ export class GaxiosInterceptorManager< T extends GaxiosOptions | GaxiosResponse, -> { - interceptorMap: Map | null>; - - constructor() { - this.interceptorMap = new Map>(); - } - - /** - * Adds an interceptor. - * - * @param {GaxiosInterceptor} interceptor the interceptor to be added. - * - * @returns {number} an identifier that can be used to remove the interceptor. - */ - addInterceptor(interceptor: GaxiosInterceptor): number { - const index = this.interceptorMap.size; - this.interceptorMap.set(index, interceptor); - - return index; - } - - /** - * Removes an interceptor. - * - * @param {number} id the previously id of the interceptor to remove. - */ - removeInterceptor(id: number) { - if (this.interceptorMap.has(id)) { - this.interceptorMap.set(id, null); - } - } - - /** - * Removes all interceptors. - */ - removeAll() { - this.interceptorMap.clear(); - } -} +> extends Set | null> {} diff --git a/test/test.getch.ts b/test/test.getch.ts index b25f91c0..26a63bbd 100644 --- a/test/test.getch.ts +++ b/test/test.getch.ts @@ -1111,7 +1111,7 @@ describe('interceptors', () => { .get('/') .reply(200, {}); const instance = new Gaxios(); - instance.interceptors.request.addInterceptor({ + instance.interceptors.request.add({ resolved: config => { config.headers = {hello: 'world'}; return Promise.resolve(config); @@ -1133,11 +1133,10 @@ describe('interceptors', () => { }) as unknown as Promise ); const instance = new Gaxios(); - const id = instance.interceptors.request.addInterceptor({ - resolved: spyFunc, - }); + const interceptor = {resolved: spyFunc}; + instance.interceptors.request.add(interceptor); await instance.request({url}); - instance.interceptors.request.removeInterceptor(id); + instance.interceptors.request.delete(interceptor); await instance.request({url}); scope.done(); assert.strictEqual(spyFunc.callCount, 1); @@ -1151,20 +1150,20 @@ describe('interceptors', () => { .get('/') .reply(200, {}); const instance = new Gaxios(); - instance.interceptors.request.addInterceptor({ + instance.interceptors.request.add({ resolved: config => { config.headers!['foo'] = 'bar'; return Promise.resolve(config); }, }); - instance.interceptors.request.addInterceptor({ + instance.interceptors.request.add({ resolved: config => { assert.strictEqual(config.headers!['foo'], 'bar'); config.headers!['bar'] = 'baz'; return Promise.resolve(config); }, }); - instance.interceptors.request.addInterceptor({ + instance.interceptors.request.add({ resolved: config => { assert.strictEqual(config.headers!['foo'], 'bar'); assert.strictEqual(config.headers!['bar'], 'baz'); @@ -1188,17 +1187,17 @@ describe('interceptors', () => { }) as unknown as Promise ); const instance = new Gaxios(); - instance.interceptors.request.addInterceptor({ + instance.interceptors.request.add({ resolved: spyFunc, }); - instance.interceptors.request.addInterceptor({ + instance.interceptors.request.add({ resolved: spyFunc, }); - instance.interceptors.request.addInterceptor({ + instance.interceptors.request.add({ resolved: spyFunc, }); await instance.request({url}); - instance.interceptors.request.removeAll(); + instance.interceptors.request.clear(); await instance.request({url}); scope.done(); assert.strictEqual(spyFunc.callCount, 3); @@ -1206,12 +1205,12 @@ describe('interceptors', () => { it('should invoke the rejected function when a previous request interceptor rejects', async () => { const instance = new Gaxios(); - instance.interceptors.request.addInterceptor({ + instance.interceptors.request.add({ resolved: () => { throw new Error('Something went wrong'); }, }); - instance.interceptors.request.addInterceptor({ + instance.interceptors.request.add({ resolved: config => { config.headers = {hello: 'world'}; return Promise.resolve(config); @@ -1229,7 +1228,7 @@ describe('interceptors', () => { it('should invoke a response interceptor when one is provided', async () => { const scope = nock(url).get('/').reply(200, {}); const instance = new Gaxios(); - instance.interceptors.response.addInterceptor({ + instance.interceptors.response.add({ resolved(response) { response.headers['hello'] = 'world'; return Promise.resolve(response); @@ -1252,11 +1251,10 @@ describe('interceptors', () => { }) as unknown as Promise ); const instance = new Gaxios(); - const id = instance.interceptors.response.addInterceptor({ - resolved: spyFunc, - }); + const interceptor = {resolved: spyFunc}; + instance.interceptors.response.add(interceptor); await instance.request({url}); - instance.interceptors.response.removeInterceptor(id); + instance.interceptors.response.delete(interceptor); await instance.request({url}); scope.done(); assert.strictEqual(spyFunc.callCount, 1); @@ -1265,20 +1263,20 @@ describe('interceptors', () => { it('should invoke multiple response interceptors in the order they were added', async () => { const scope = nock(url).get('/').reply(200, {}); const instance = new Gaxios(); - instance.interceptors.response.addInterceptor({ + instance.interceptors.response.add({ resolved: response => { response.headers!['foo'] = 'bar'; return Promise.resolve(response); }, }); - instance.interceptors.response.addInterceptor({ + instance.interceptors.response.add({ resolved: response => { assert.strictEqual(response.headers!['foo'], 'bar'); response.headers!['bar'] = 'baz'; return Promise.resolve(response); }, }); - instance.interceptors.response.addInterceptor({ + instance.interceptors.response.add({ resolved: response => { assert.strictEqual(response.headers!['foo'], 'bar'); assert.strictEqual(response.headers!['bar'], 'baz'); @@ -1305,17 +1303,17 @@ describe('interceptors', () => { }) as unknown as Promise ); const instance = new Gaxios(); - instance.interceptors.response.addInterceptor({ + instance.interceptors.response.add({ resolved: spyFunc, }); - instance.interceptors.response.addInterceptor({ + instance.interceptors.response.add({ resolved: spyFunc, }); - instance.interceptors.response.addInterceptor({ + instance.interceptors.response.add({ resolved: spyFunc, }); await instance.request({url}); - instance.interceptors.response.removeAll(); + instance.interceptors.response.clear(); await instance.request({url}); scope.done(); assert.strictEqual(spyFunc.callCount, 3); @@ -1324,7 +1322,7 @@ describe('interceptors', () => { it('should invoke the rejected function when a request has an error', async () => { const scope = nock(url).get('/').reply(404, {}); const instance = new Gaxios(); - instance.interceptors.response.addInterceptor({ + instance.interceptors.response.add({ rejected: err => { assert.strictEqual(err.status, 404); },