diff --git a/packages/requester-common/src/types/Request.ts b/packages/requester-common/src/types/Request.ts index 45f75178d..2eaed9055 100644 --- a/packages/requester-common/src/types/Request.ts +++ b/packages/requester-common/src/types/Request.ts @@ -30,4 +30,9 @@ export type Request = { * The data to be transfered to the server. */ readonly data: string | undefined; + + /** + * options passed to the network request function + */ + readonly requesterOptions?: any; }; diff --git a/packages/requester-node-http/src/__tests__/unit/node-http-requester.test.ts b/packages/requester-node-http/src/__tests__/unit/node-http-requester.test.ts index 7a0b17ae3..ac70c7c1a 100644 --- a/packages/requester-node-http/src/__tests__/unit/node-http-requester.test.ts +++ b/packages/requester-node-http/src/__tests__/unit/node-http-requester.test.ts @@ -216,7 +216,7 @@ describe('timeout handling', () => { }); }); -describe('error handling', (): void => { +describe('error handling', () => { it('resolves dns not found', async () => { const request = { url: 'https://this-dont-exist.algolia.com', @@ -251,3 +251,27 @@ describe('error handling', (): void => { expect(response.isTimedOut).toBe(false); }); }); + +describe('options', () => { + it('passes `requesterOptions` to http.request()', async () => { + const request = { + ...requestStub, + requesterOptions: { + // override any parameter sent to http[s].request + // we can only test those which nock can handle, like method + method: 'GET', + }, + }; + + const body = { response: 'foo' }; + + nock('https://algolia-dns.net') + .get('/foo') + .query({ 'x-algolia-header': 'foo' }) + .reply(200, body); + + const response = await requester.send(request); + + expect(response.content).toEqual(body); + }); +}); diff --git a/packages/requester-node-http/src/createNodeHttpRequester.ts b/packages/requester-node-http/src/createNodeHttpRequester.ts index fa9b9c876..29a76aaf5 100644 --- a/packages/requester-node-http/src/createNodeHttpRequester.ts +++ b/packages/requester-node-http/src/createNodeHttpRequester.ts @@ -35,6 +35,7 @@ export function createNodeHttpRequester({ method: request.method, headers: request.headers, ...(url.port !== undefined ? { port: url.port || '' } : {}), + ...(request.requesterOptions ? request.requesterOptions : {}), }; const req = (url.protocol === 'https:' ? https : http).request(options, response => { diff --git a/packages/transporter/src/__tests__/unit/request-options.test.ts b/packages/transporter/src/__tests__/unit/request-options.test.ts index 3b3c86051..510e42d5c 100644 --- a/packages/transporter/src/__tests__/unit/request-options.test.ts +++ b/packages/transporter/src/__tests__/unit/request-options.test.ts @@ -53,4 +53,11 @@ describe('request options', () => { expect(result.data).toBeUndefined(); }); + + it('passes requesterOptions through', () => { + const requesterOptions = { time: new Date() }; + const result = createMappedRequestOptions({ requesterOptions }); + + expect(result.requesterOptions).toEqual(requesterOptions); + }); }); diff --git a/packages/transporter/src/concerns/retryableRequest.ts b/packages/transporter/src/concerns/retryableRequest.ts index 6ea17c2e1..a92b4a02c 100644 --- a/packages/transporter/src/concerns/retryableRequest.ts +++ b/packages/transporter/src/concerns/retryableRequest.ts @@ -72,6 +72,7 @@ export function retryableRequest( url: serializeUrl(host, request.path, queryParameters), connectTimeout: getTimeout(timeoutsCount, transporter.timeouts.connect), responseTimeout: getTimeout(timeoutsCount, requestOptions.timeout as number), + requesterOptions: requestOptions.requesterOptions, }; /** diff --git a/packages/transporter/src/createMappedRequestOptions.ts b/packages/transporter/src/createMappedRequestOptions.ts index 2054a3ddb..ade8dd521 100644 --- a/packages/transporter/src/createMappedRequestOptions.ts +++ b/packages/transporter/src/createMappedRequestOptions.ts @@ -1,5 +1,14 @@ import { MappedRequestOptions, RequestOptions } from '.'; +const SPECIAL_KEYS = [ + 'timeout', + 'headers', + 'queryParameters', + 'data', + 'cacheable', + 'requesterOptions', +]; + export function createMappedRequestOptions( requestOptions?: RequestOptions, timeout?: number @@ -9,7 +18,7 @@ export function createMappedRequestOptions( const data: Record = options.data || {}; Object.keys(options).forEach(key => { - if (['timeout', 'headers', 'queryParameters', 'data', 'cacheable'].indexOf(key) === -1) { + if (SPECIAL_KEYS.indexOf(key) === -1) { data[key] = options[key]; // eslint-disable-line functional/immutable-data } }); @@ -20,5 +29,6 @@ export function createMappedRequestOptions( headers: options.headers || {}, queryParameters: options.queryParameters || {}, cacheable: options.cacheable, + ...(options.requesterOptions ? { requesterOptions: options.requesterOptions } : {}), }; } diff --git a/packages/transporter/src/types/MappedRequestOptions.ts b/packages/transporter/src/types/MappedRequestOptions.ts index fc11ab53f..11dc032ea 100644 --- a/packages/transporter/src/types/MappedRequestOptions.ts +++ b/packages/transporter/src/types/MappedRequestOptions.ts @@ -23,4 +23,9 @@ export type MappedRequestOptions = { * The data to be transfered to the server. */ readonly data?: Record; + + /** + * options passed to the network request function + */ + readonly requesterOptions?: any; }; diff --git a/packages/transporter/src/types/RequestOptions.ts b/packages/transporter/src/types/RequestOptions.ts index 018843e5d..2a01687b2 100644 --- a/packages/transporter/src/types/RequestOptions.ts +++ b/packages/transporter/src/types/RequestOptions.ts @@ -6,7 +6,7 @@ export type RequestOptions = { readonly cacheable?: boolean; /** - * Custom timeout for the request. Note that, in normal situacions + * Custom timeout for the request. Note that, in normal situations * the given timeout will be applied. But the transporter layer may * increase this timeout if there is need for it. */ @@ -14,22 +14,27 @@ export type RequestOptions = { /** * Custom headers for the request. This headers are - * going to be merged the transporter headers. + * going to be merged with the transporter headers. */ readonly headers?: Readonly>; /** * Custom query parameters for the request. This query parameters are - * going to be merged the transporter query parameters. + * going to be merged with the transporter query parameters. */ readonly queryParameters?: Record; /** * Custom data for the request. This data are - * going to be merged the transporter data. + * going to be merged with the transporter data. */ readonly data?: Record; + /** + * options passed to the network request function + */ + readonly requesterOptions?: any; + /** * Additional request body values. It's only taken in * consideration in `POST` and `PUT` requests.