From 9947d657aa5607e81b7e108beccf02e88c9ce8df Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Fri, 1 Oct 2021 11:09:16 -0700 Subject: [PATCH 1/3] Add errorInterceptors feature to ES UI Shared request module. --- src/plugins/es_ui_shared/public/index.ts | 1 + .../es_ui_shared/public/request/index.ts | 7 ++++++- .../request/send_request.test.helpers.ts | 7 +++++-- .../public/request/send_request.test.ts | 16 ++++++++++++++++ .../public/request/send_request.ts | 18 ++++++++++++++++-- .../public/request/use_request.test.ts | 12 ++++++++++++ .../es_ui_shared/public/request/use_request.ts | 15 ++++++++++++--- 7 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/plugins/es_ui_shared/public/index.ts b/src/plugins/es_ui_shared/public/index.ts index 9db00bc4be8df..eb3b744117a17 100644 --- a/src/plugins/es_ui_shared/public/index.ts +++ b/src/plugins/es_ui_shared/public/index.ts @@ -30,6 +30,7 @@ export { UseRequestResponse, sendRequest, useRequest, + ResponseInterceptor, } from './request'; export { indices } from './indices'; diff --git a/src/plugins/es_ui_shared/public/request/index.ts b/src/plugins/es_ui_shared/public/request/index.ts index da407d0013037..02544720a847b 100644 --- a/src/plugins/es_ui_shared/public/request/index.ts +++ b/src/plugins/es_ui_shared/public/request/index.ts @@ -6,5 +6,10 @@ * Side Public License, v 1. */ -export { SendRequestConfig, SendRequestResponse, sendRequest } from './send_request'; +export { + SendRequestConfig, + SendRequestResponse, + sendRequest, + ResponseInterceptor, +} from './send_request'; export { UseRequestConfig, UseRequestResponse, useRequest } from './use_request'; diff --git a/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts b/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts index 3ef33b651f4d2..ef7eac84126ad 100644 --- a/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts +++ b/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts @@ -19,7 +19,9 @@ export interface SendRequestHelpers { getSendRequestSpy: () => sinon.SinonStub; sendSuccessRequest: () => Promise; getSuccessResponse: () => SendRequestResponse; - sendErrorRequest: () => Promise; + sendErrorRequest: ( + errorInterceptors?: SendRequestConfig['errorInterceptors'] + ) => Promise; getErrorResponse: () => SendRequestResponse; } @@ -62,7 +64,8 @@ export const createSendRequestHelpers = (): SendRequestHelpers => { }) ) .rejects(errorResponse); - const sendErrorRequest = () => sendRequest({ ...errorRequest }); + const sendErrorRequest = (errorInterceptors?: SendRequestConfig['errorInterceptors']) => + sendRequest({ ...errorRequest, errorInterceptors }); const getErrorResponse = () => ({ data: null, error: errorResponse.response.data, diff --git a/src/plugins/es_ui_shared/public/request/send_request.test.ts b/src/plugins/es_ui_shared/public/request/send_request.test.ts index 3bdb49c6e8206..95217e1f43c04 100644 --- a/src/plugins/es_ui_shared/public/request/send_request.test.ts +++ b/src/plugins/es_ui_shared/public/request/send_request.test.ts @@ -33,4 +33,20 @@ describe('sendRequest function', () => { sinon.assert.calledOnce(getSendRequestSpy()); expect(error).toEqual(getErrorResponse()); }); + + it('applies errorInterceptors to errors', async () => { + const { sendErrorRequest, getSendRequestSpy } = helpers; + const errorInterceptors = [ + (error: any) => ['Error is:', error.statusText], + (interceptedError: string[]) => interceptedError.join(' '), + ]; + + // For some reason sinon isn't throwing an error on rejection, as an awaited Promise normally would. + const error = await sendErrorRequest(errorInterceptors); + sinon.assert.calledOnce(getSendRequestSpy()); + expect(error).toEqual({ + data: null, + error: 'Error is: Error message', + }); + }); }); diff --git a/src/plugins/es_ui_shared/public/request/send_request.ts b/src/plugins/es_ui_shared/public/request/send_request.ts index 11ab99cfb6978..ccf7434214f2e 100644 --- a/src/plugins/es_ui_shared/public/request/send_request.ts +++ b/src/plugins/es_ui_shared/public/request/send_request.ts @@ -8,6 +8,8 @@ import { HttpSetup, HttpFetchQuery } from '../../../../../src/core/public'; +export type ResponseInterceptor = (response: any) => any; + export interface SendRequestConfig { path: string; method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head'; @@ -18,6 +20,7 @@ export interface SendRequestConfig { * HttpFetchOptions#asSystemRequest. */ asSystemRequest?: boolean; + errorInterceptors?: ResponseInterceptor[]; } export interface SendRequestResponse { @@ -25,9 +28,18 @@ export interface SendRequestResponse { error: E | null; } +// Pass the response sequentially through each interceptor, providing +// the output of one interceptor as the input of the next interceptor. +const applyInterceptors = (response: any, interceptors: ResponseInterceptor[] = []): any => { + return interceptors.reduce( + (interceptedResponse, interceptor) => interceptor(interceptedResponse), + response + ); +}; + export const sendRequest = async ( httpClient: HttpSetup, - { path, method, body, query, asSystemRequest }: SendRequestConfig + { path, method, body, query, asSystemRequest, errorInterceptors }: SendRequestConfig ): Promise> => { try { const stringifiedBody = typeof body === 'string' ? body : JSON.stringify(body); @@ -42,9 +54,11 @@ export const sendRequest = async ( error: null, }; } catch (e) { + const responseError = e.response?.data ?? e.body; + const interceptedError = applyInterceptors(responseError, errorInterceptors); return { data: null, - error: e.response?.data ?? e.body, + error: interceptedError, }; } }; diff --git a/src/plugins/es_ui_shared/public/request/use_request.test.ts b/src/plugins/es_ui_shared/public/request/use_request.test.ts index 68edde1336728..c1790fd7d4079 100644 --- a/src/plugins/es_ui_shared/public/request/use_request.test.ts +++ b/src/plugins/es_ui_shared/public/request/use_request.test.ts @@ -117,6 +117,18 @@ describe('useRequest hook', () => { expect(hookResult.error).toBe(getErrorResponse().error); }); + it('applies errorInterceptors to errors', async () => { + const { setupErrorRequest, completeRequest, hookResult } = helpers; + const errorInterceptors = [ + (error: any) => ['Error is:', error.statusText], + (interceptedError: string[]) => interceptedError.join(' '), + ]; + + setupErrorRequest({ errorInterceptors }); + await completeRequest(); + expect(hookResult.error).toBe('Error is: Error message'); + }); + it('surfaces body-shaped errors from requests', async () => { const { setupErrorWithBodyRequest, completeRequest, hookResult, getErrorWithBodyResponse } = helpers; diff --git a/src/plugins/es_ui_shared/public/request/use_request.ts b/src/plugins/es_ui_shared/public/request/use_request.ts index 33085bdbf4478..8d0fff0494fb0 100644 --- a/src/plugins/es_ui_shared/public/request/use_request.ts +++ b/src/plugins/es_ui_shared/public/request/use_request.ts @@ -27,7 +27,16 @@ export interface UseRequestResponse { export const useRequest = ( httpClient: HttpSetup, - { path, method, query, body, pollIntervalMs, initialData, deserializer }: UseRequestConfig + { + path, + method, + query, + body, + pollIntervalMs, + initialData, + deserializer, + errorInterceptors, + }: UseRequestConfig ): UseRequestResponse => { const isMounted = useRef(false); @@ -80,7 +89,7 @@ export const useRequest = ( // Any requests that are sent in the background (without user interaction) should be flagged as "system requests". This should not be // confused with any terminology in Elasticsearch. This is a Kibana-specific construct that allows the server to differentiate between // user-initiated and requests "system"-initiated requests, for purposes like security features. - const requestPayload = { ...requestBody, asSystemRequest }; + const requestPayload = { ...requestBody, asSystemRequest, errorInterceptors }; const response = await sendRequest(httpClient, requestPayload); const { data: serializedResponseData, error: responseError } = response; @@ -106,7 +115,7 @@ export const useRequest = ( // Setting isLoading to false also acts as a signal for scheduling the next poll request. setIsLoading(false); }, - [requestBody, httpClient, deserializer, clearPollInterval] + [requestBody, httpClient, deserializer, clearPollInterval, errorInterceptors] ); const scheduleRequest = useCallback(() => { From b74c6855e06f74c3584af2689b9522ca7667eef2 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Sat, 2 Oct 2021 12:56:04 -0700 Subject: [PATCH 2/3] Expand interceptors to handle both errors and successful responses. Focus interceptors on executing side effects, not mutating responses. --- .../request/send_request.test.helpers.ts | 13 ++++--- .../public/request/send_request.test.ts | 33 +++++++++------- .../public/request/send_request.ts | 38 ++++++++++--------- .../public/request/use_request.test.ts | 12 ------ .../public/request/use_request.ts | 6 +-- 5 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts b/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts index ef7eac84126ad..4e47835ff2cf5 100644 --- a/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts +++ b/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts @@ -17,10 +17,12 @@ import { export interface SendRequestHelpers { getSendRequestSpy: () => sinon.SinonStub; - sendSuccessRequest: () => Promise; + sendSuccessRequest: ( + responseInterceptors?: SendRequestConfig['responseInterceptors'] + ) => Promise; getSuccessResponse: () => SendRequestResponse; sendErrorRequest: ( - errorInterceptors?: SendRequestConfig['errorInterceptors'] + responseInterceptors?: SendRequestConfig['responseInterceptors'] ) => Promise; getErrorResponse: () => SendRequestResponse; } @@ -51,7 +53,8 @@ export const createSendRequestHelpers = (): SendRequestHelpers => { }) ) .resolves(successResponse); - const sendSuccessRequest = () => sendRequest({ ...successRequest }); + const sendSuccessRequest = (responseInterceptors?: SendRequestConfig['responseInterceptors']) => + sendRequest({ ...successRequest, responseInterceptors }); const getSuccessResponse = () => ({ data: successResponse.data, error: null }); // Set up failed request helpers. @@ -64,8 +67,8 @@ export const createSendRequestHelpers = (): SendRequestHelpers => { }) ) .rejects(errorResponse); - const sendErrorRequest = (errorInterceptors?: SendRequestConfig['errorInterceptors']) => - sendRequest({ ...errorRequest, errorInterceptors }); + const sendErrorRequest = (responseInterceptors?: SendRequestConfig['responseInterceptors']) => + sendRequest({ ...errorRequest, responseInterceptors }); const getErrorResponse = () => ({ data: null, error: errorResponse.response.data, diff --git a/src/plugins/es_ui_shared/public/request/send_request.test.ts b/src/plugins/es_ui_shared/public/request/send_request.test.ts index 95217e1f43c04..247cc419bba66 100644 --- a/src/plugins/es_ui_shared/public/request/send_request.test.ts +++ b/src/plugins/es_ui_shared/public/request/send_request.test.ts @@ -29,24 +29,29 @@ describe('sendRequest function', () => { const { sendErrorRequest, getSendRequestSpy, getErrorResponse } = helpers; // For some reason sinon isn't throwing an error on rejection, as an awaited Promise normally would. - const error = await sendErrorRequest(); + const errorResponse = await sendErrorRequest(); sinon.assert.calledOnce(getSendRequestSpy()); - expect(error).toEqual(getErrorResponse()); + expect(errorResponse).toEqual(getErrorResponse()); }); - it('applies errorInterceptors to errors', async () => { - const { sendErrorRequest, getSendRequestSpy } = helpers; - const errorInterceptors = [ - (error: any) => ['Error is:', error.statusText], - (interceptedError: string[]) => interceptedError.join(' '), - ]; + it('calls responseInterceptors with successful responses', async () => { + const { sendSuccessRequest, getSuccessResponse } = helpers; + const successInterceptorSpy = sinon.spy(); + const successInterceptors = [successInterceptorSpy]; + + await sendSuccessRequest(successInterceptors); + sinon.assert.calledOnce(successInterceptorSpy); + sinon.assert.calledWith(successInterceptorSpy, getSuccessResponse()); + }); + + it('calls responseInterceptors with errors', async () => { + const { sendErrorRequest, getErrorResponse } = helpers; + const errorInterceptorSpy = sinon.spy(); + const errorInterceptors = [errorInterceptorSpy]; // For some reason sinon isn't throwing an error on rejection, as an awaited Promise normally would. - const error = await sendErrorRequest(errorInterceptors); - sinon.assert.calledOnce(getSendRequestSpy()); - expect(error).toEqual({ - data: null, - error: 'Error is: Error message', - }); + await sendErrorRequest(errorInterceptors); + sinon.assert.calledOnce(errorInterceptorSpy); + sinon.assert.calledWith(errorInterceptorSpy, getErrorResponse()); }); }); diff --git a/src/plugins/es_ui_shared/public/request/send_request.ts b/src/plugins/es_ui_shared/public/request/send_request.ts index ccf7434214f2e..33d481359cf9e 100644 --- a/src/plugins/es_ui_shared/public/request/send_request.ts +++ b/src/plugins/es_ui_shared/public/request/send_request.ts @@ -8,7 +8,7 @@ import { HttpSetup, HttpFetchQuery } from '../../../../../src/core/public'; -export type ResponseInterceptor = (response: any) => any; +export type ResponseInterceptor = ({ data, error }: { data: any; error: any }) => void; export interface SendRequestConfig { path: string; @@ -20,7 +20,7 @@ export interface SendRequestConfig { * HttpFetchOptions#asSystemRequest. */ asSystemRequest?: boolean; - errorInterceptors?: ResponseInterceptor[]; + responseInterceptors?: ResponseInterceptor[]; } export interface SendRequestResponse { @@ -28,37 +28,41 @@ export interface SendRequestResponse { error: E | null; } -// Pass the response sequentially through each interceptor, providing -// the output of one interceptor as the input of the next interceptor. -const applyInterceptors = (response: any, interceptors: ResponseInterceptor[] = []): any => { - return interceptors.reduce( - (interceptedResponse, interceptor) => interceptor(interceptedResponse), - response - ); +// Pass the response sequentially through each interceptor, allowing for +// side effects to be run. +const updateResponseInterceptors = ( + response: any, + responseInterceptors: ResponseInterceptor[] = [] +) => { + responseInterceptors.forEach((interceptor) => interceptor(response)); }; export const sendRequest = async ( httpClient: HttpSetup, - { path, method, body, query, asSystemRequest, errorInterceptors }: SendRequestConfig + { path, method, body, query, asSystemRequest, responseInterceptors }: SendRequestConfig ): Promise> => { try { const stringifiedBody = typeof body === 'string' ? body : JSON.stringify(body); - const response = await httpClient[method](path, { + const rawResponse = await httpClient[method](path, { body: stringifiedBody, query, asSystemRequest, }); - return { - data: response.data ? response.data : response, + const response = { + data: rawResponse.data ? rawResponse.data : rawResponse, error: null, }; + + updateResponseInterceptors(response, responseInterceptors); + return response; } catch (e) { - const responseError = e.response?.data ?? e.body; - const interceptedError = applyInterceptors(responseError, errorInterceptors); - return { + const response = { data: null, - error: interceptedError, + error: e.response?.data ?? e.body, }; + + updateResponseInterceptors(response, responseInterceptors); + return response; } }; diff --git a/src/plugins/es_ui_shared/public/request/use_request.test.ts b/src/plugins/es_ui_shared/public/request/use_request.test.ts index c1790fd7d4079..68edde1336728 100644 --- a/src/plugins/es_ui_shared/public/request/use_request.test.ts +++ b/src/plugins/es_ui_shared/public/request/use_request.test.ts @@ -117,18 +117,6 @@ describe('useRequest hook', () => { expect(hookResult.error).toBe(getErrorResponse().error); }); - it('applies errorInterceptors to errors', async () => { - const { setupErrorRequest, completeRequest, hookResult } = helpers; - const errorInterceptors = [ - (error: any) => ['Error is:', error.statusText], - (interceptedError: string[]) => interceptedError.join(' '), - ]; - - setupErrorRequest({ errorInterceptors }); - await completeRequest(); - expect(hookResult.error).toBe('Error is: Error message'); - }); - it('surfaces body-shaped errors from requests', async () => { const { setupErrorWithBodyRequest, completeRequest, hookResult, getErrorWithBodyResponse } = helpers; diff --git a/src/plugins/es_ui_shared/public/request/use_request.ts b/src/plugins/es_ui_shared/public/request/use_request.ts index 8d0fff0494fb0..8bac129af134c 100644 --- a/src/plugins/es_ui_shared/public/request/use_request.ts +++ b/src/plugins/es_ui_shared/public/request/use_request.ts @@ -35,7 +35,7 @@ export const useRequest = ( pollIntervalMs, initialData, deserializer, - errorInterceptors, + responseInterceptors, }: UseRequestConfig ): UseRequestResponse => { const isMounted = useRef(false); @@ -89,7 +89,7 @@ export const useRequest = ( // Any requests that are sent in the background (without user interaction) should be flagged as "system requests". This should not be // confused with any terminology in Elasticsearch. This is a Kibana-specific construct that allows the server to differentiate between // user-initiated and requests "system"-initiated requests, for purposes like security features. - const requestPayload = { ...requestBody, asSystemRequest, errorInterceptors }; + const requestPayload = { ...requestBody, asSystemRequest, responseInterceptors }; const response = await sendRequest(httpClient, requestPayload); const { data: serializedResponseData, error: responseError } = response; @@ -115,7 +115,7 @@ export const useRequest = ( // Setting isLoading to false also acts as a signal for scheduling the next poll request. setIsLoading(false); }, - [requestBody, httpClient, deserializer, clearPollInterval, errorInterceptors] + [requestBody, httpClient, deserializer, clearPollInterval, responseInterceptors] ); const scheduleRequest = useCallback(() => { From 7ff8d58d35b06c09e726d6d1a3cf0d8c28757427 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Tue, 5 Oct 2021 20:45:46 -0700 Subject: [PATCH 3/3] Rename responseInterceptors -> responseHnadlers. Add comment to interface. --- .../es_ui_shared/public/request/index.ts | 2 +- .../request/send_request.test.helpers.ts | 12 +++++----- .../public/request/send_request.test.ts | 24 +++++++++---------- .../public/request/send_request.ts | 21 ++++++++-------- .../public/request/use_request.ts | 6 ++--- 5 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/plugins/es_ui_shared/public/request/index.ts b/src/plugins/es_ui_shared/public/request/index.ts index 02544720a847b..c3c20ce262544 100644 --- a/src/plugins/es_ui_shared/public/request/index.ts +++ b/src/plugins/es_ui_shared/public/request/index.ts @@ -10,6 +10,6 @@ export { SendRequestConfig, SendRequestResponse, sendRequest, - ResponseInterceptor, + ResponseHandler, } from './send_request'; export { UseRequestConfig, UseRequestResponse, useRequest } from './use_request'; diff --git a/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts b/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts index 4e47835ff2cf5..90c742d7dfb2e 100644 --- a/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts +++ b/src/plugins/es_ui_shared/public/request/send_request.test.helpers.ts @@ -18,11 +18,11 @@ import { export interface SendRequestHelpers { getSendRequestSpy: () => sinon.SinonStub; sendSuccessRequest: ( - responseInterceptors?: SendRequestConfig['responseInterceptors'] + responseHandlers?: SendRequestConfig['responseHandlers'] ) => Promise; getSuccessResponse: () => SendRequestResponse; sendErrorRequest: ( - responseInterceptors?: SendRequestConfig['responseInterceptors'] + responseHandlers?: SendRequestConfig['responseHandlers'] ) => Promise; getErrorResponse: () => SendRequestResponse; } @@ -53,8 +53,8 @@ export const createSendRequestHelpers = (): SendRequestHelpers => { }) ) .resolves(successResponse); - const sendSuccessRequest = (responseInterceptors?: SendRequestConfig['responseInterceptors']) => - sendRequest({ ...successRequest, responseInterceptors }); + const sendSuccessRequest = (responseHandlers?: SendRequestConfig['responseHandlers']) => + sendRequest({ ...successRequest, responseHandlers }); const getSuccessResponse = () => ({ data: successResponse.data, error: null }); // Set up failed request helpers. @@ -67,8 +67,8 @@ export const createSendRequestHelpers = (): SendRequestHelpers => { }) ) .rejects(errorResponse); - const sendErrorRequest = (responseInterceptors?: SendRequestConfig['responseInterceptors']) => - sendRequest({ ...errorRequest, responseInterceptors }); + const sendErrorRequest = (responseHandlers?: SendRequestConfig['responseHandlers']) => + sendRequest({ ...errorRequest, responseHandlers }); const getErrorResponse = () => ({ data: null, error: errorResponse.response.data, diff --git a/src/plugins/es_ui_shared/public/request/send_request.test.ts b/src/plugins/es_ui_shared/public/request/send_request.test.ts index 247cc419bba66..7174ac51b64c8 100644 --- a/src/plugins/es_ui_shared/public/request/send_request.test.ts +++ b/src/plugins/es_ui_shared/public/request/send_request.test.ts @@ -34,24 +34,24 @@ describe('sendRequest function', () => { expect(errorResponse).toEqual(getErrorResponse()); }); - it('calls responseInterceptors with successful responses', async () => { + it('calls responseHandlers with successful responses', async () => { const { sendSuccessRequest, getSuccessResponse } = helpers; - const successInterceptorSpy = sinon.spy(); - const successInterceptors = [successInterceptorSpy]; + const successHandlerSpy = sinon.spy(); + const successHandlers = [successHandlerSpy]; - await sendSuccessRequest(successInterceptors); - sinon.assert.calledOnce(successInterceptorSpy); - sinon.assert.calledWith(successInterceptorSpy, getSuccessResponse()); + await sendSuccessRequest(successHandlers); + sinon.assert.calledOnce(successHandlerSpy); + sinon.assert.calledWith(successHandlerSpy, getSuccessResponse()); }); - it('calls responseInterceptors with errors', async () => { + it('calls responseHandlers with errors', async () => { const { sendErrorRequest, getErrorResponse } = helpers; - const errorInterceptorSpy = sinon.spy(); - const errorInterceptors = [errorInterceptorSpy]; + const errorHandlerSpy = sinon.spy(); + const errorHandlers = [errorHandlerSpy]; // For some reason sinon isn't throwing an error on rejection, as an awaited Promise normally would. - await sendErrorRequest(errorInterceptors); - sinon.assert.calledOnce(errorInterceptorSpy); - sinon.assert.calledWith(errorInterceptorSpy, getErrorResponse()); + await sendErrorRequest(errorHandlers); + sinon.assert.calledOnce(errorHandlerSpy); + sinon.assert.calledWith(errorHandlerSpy, getErrorResponse()); }); }); diff --git a/src/plugins/es_ui_shared/public/request/send_request.ts b/src/plugins/es_ui_shared/public/request/send_request.ts index 33d481359cf9e..51d81bb1bbebd 100644 --- a/src/plugins/es_ui_shared/public/request/send_request.ts +++ b/src/plugins/es_ui_shared/public/request/send_request.ts @@ -8,7 +8,7 @@ import { HttpSetup, HttpFetchQuery } from '../../../../../src/core/public'; -export type ResponseInterceptor = ({ data, error }: { data: any; error: any }) => void; +export type ResponseHandler = ({ data, error }: { data: any; error: any }) => void; export interface SendRequestConfig { path: string; @@ -20,7 +20,11 @@ export interface SendRequestConfig { * HttpFetchOptions#asSystemRequest. */ asSystemRequest?: boolean; - responseInterceptors?: ResponseInterceptor[]; + /** + * Optional handlers for triggering side effects based on a request's + * successful response or errror. These don't mutate responses or errors. + */ + responseHandlers?: ResponseHandler[]; } export interface SendRequestResponse { @@ -30,16 +34,13 @@ export interface SendRequestResponse { // Pass the response sequentially through each interceptor, allowing for // side effects to be run. -const updateResponseInterceptors = ( - response: any, - responseInterceptors: ResponseInterceptor[] = [] -) => { - responseInterceptors.forEach((interceptor) => interceptor(response)); +const updateResponseHandlers = (response: any, responseHandlers: ResponseHandler[] = []) => { + responseHandlers.forEach((interceptor) => interceptor(response)); }; export const sendRequest = async ( httpClient: HttpSetup, - { path, method, body, query, asSystemRequest, responseInterceptors }: SendRequestConfig + { path, method, body, query, asSystemRequest, responseHandlers }: SendRequestConfig ): Promise> => { try { const stringifiedBody = typeof body === 'string' ? body : JSON.stringify(body); @@ -54,7 +55,7 @@ export const sendRequest = async ( error: null, }; - updateResponseInterceptors(response, responseInterceptors); + updateResponseHandlers(response, responseHandlers); return response; } catch (e) { const response = { @@ -62,7 +63,7 @@ export const sendRequest = async ( error: e.response?.data ?? e.body, }; - updateResponseInterceptors(response, responseInterceptors); + updateResponseHandlers(response, responseHandlers); return response; } }; diff --git a/src/plugins/es_ui_shared/public/request/use_request.ts b/src/plugins/es_ui_shared/public/request/use_request.ts index 8bac129af134c..03643b5012df0 100644 --- a/src/plugins/es_ui_shared/public/request/use_request.ts +++ b/src/plugins/es_ui_shared/public/request/use_request.ts @@ -35,7 +35,7 @@ export const useRequest = ( pollIntervalMs, initialData, deserializer, - responseInterceptors, + responseHandlers, }: UseRequestConfig ): UseRequestResponse => { const isMounted = useRef(false); @@ -89,7 +89,7 @@ export const useRequest = ( // Any requests that are sent in the background (without user interaction) should be flagged as "system requests". This should not be // confused with any terminology in Elasticsearch. This is a Kibana-specific construct that allows the server to differentiate between // user-initiated and requests "system"-initiated requests, for purposes like security features. - const requestPayload = { ...requestBody, asSystemRequest, responseInterceptors }; + const requestPayload = { ...requestBody, asSystemRequest, responseHandlers }; const response = await sendRequest(httpClient, requestPayload); const { data: serializedResponseData, error: responseError } = response; @@ -115,7 +115,7 @@ export const useRequest = ( // Setting isLoading to false also acts as a signal for scheduling the next poll request. setIsLoading(false); }, - [requestBody, httpClient, deserializer, clearPollInterval, responseInterceptors] + [requestBody, httpClient, deserializer, clearPollInterval, responseHandlers] ); const scheduleRequest = useCallback(() => {