Skip to content

Commit

Permalink
Revert changes to request module and support handling responses globa…
Browse files Browse the repository at this point in the history
…lly in local api module.
  • Loading branch information
cjcenizal committed Oct 7, 2021
1 parent 1cd7838 commit 2f03b10
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 142 deletions.
1 change: 0 additions & 1 deletion src/plugins/es_ui_shared/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export {
UseRequestResponse,
sendRequest,
useRequest,
ResponseInterceptor,
} from './request';

export { indices } from './indices';
Expand Down
7 changes: 1 addition & 6 deletions src/plugins/es_ui_shared/public/request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,5 @@
* Side Public License, v 1.
*/

export {
SendRequestConfig,
SendRequestResponse,
sendRequest,
ResponseInterceptor,
} from './send_request';
export { SendRequestConfig, SendRequestResponse, sendRequest } from './send_request';
export { UseRequestConfig, UseRequestResponse, useRequest } from './use_request';
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,9 @@ import {

export interface SendRequestHelpers {
getSendRequestSpy: () => sinon.SinonStub;
sendSuccessRequest: (
responseInterceptors?: SendRequestConfig['responseInterceptors']
) => Promise<SendRequestResponse>;
sendSuccessRequest: () => Promise<SendRequestResponse>;
getSuccessResponse: () => SendRequestResponse;
sendErrorRequest: (
responseInterceptors?: SendRequestConfig['responseInterceptors']
) => Promise<SendRequestResponse>;
sendErrorRequest: () => Promise<SendRequestResponse>;
getErrorResponse: () => SendRequestResponse;
}

Expand Down Expand Up @@ -53,8 +49,7 @@ export const createSendRequestHelpers = (): SendRequestHelpers => {
})
)
.resolves(successResponse);
const sendSuccessRequest = (responseInterceptors?: SendRequestConfig['responseInterceptors']) =>
sendRequest({ ...successRequest, responseInterceptors });
const sendSuccessRequest = () => sendRequest({ ...successRequest });
const getSuccessResponse = () => ({ data: successResponse.data, error: null });

// Set up failed request helpers.
Expand All @@ -67,8 +62,7 @@ export const createSendRequestHelpers = (): SendRequestHelpers => {
})
)
.rejects(errorResponse);
const sendErrorRequest = (responseInterceptors?: SendRequestConfig['responseInterceptors']) =>
sendRequest({ ...errorRequest, responseInterceptors });
const sendErrorRequest = () => sendRequest({ ...errorRequest });
const getErrorResponse = () => ({
data: null,
error: errorResponse.response.data,
Expand Down
25 changes: 2 additions & 23 deletions src/plugins/es_ui_shared/public/request/send_request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,8 @@ 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 errorResponse = await sendErrorRequest();
const error = await sendErrorRequest();
sinon.assert.calledOnce(getSendRequestSpy());
expect(errorResponse).toEqual(getErrorResponse());
});

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.
await sendErrorRequest(errorInterceptors);
sinon.assert.calledOnce(errorInterceptorSpy);
sinon.assert.calledWith(errorInterceptorSpy, getErrorResponse());
expect(error).toEqual(getErrorResponse());
});
});
28 changes: 5 additions & 23 deletions src/plugins/es_ui_shared/public/request/send_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

import { HttpSetup, HttpFetchQuery } from '../../../../../src/core/public';

export type ResponseInterceptor = ({ data, error }: { data: any; error: any }) => void;

export interface SendRequestConfig {
path: string;
method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head';
Expand All @@ -20,49 +18,33 @@ export interface SendRequestConfig {
* HttpFetchOptions#asSystemRequest.
*/
asSystemRequest?: boolean;
responseInterceptors?: ResponseInterceptor[];
}

export interface SendRequestResponse<D = any, E = any> {
data: D | null;
error: E | null;
}

// 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 <D = any, E = any>(
httpClient: HttpSetup,
{ path, method, body, query, asSystemRequest, responseInterceptors }: SendRequestConfig
{ path, method, body, query, asSystemRequest }: SendRequestConfig
): Promise<SendRequestResponse<D, E>> => {
try {
const stringifiedBody = typeof body === 'string' ? body : JSON.stringify(body);
const rawResponse = await httpClient[method](path, {
const response = await httpClient[method](path, {
body: stringifiedBody,
query,
asSystemRequest,
});

const response = {
data: rawResponse.data ? rawResponse.data : rawResponse,
return {
data: response.data ? response.data : response,
error: null,
};

updateResponseInterceptors(response, responseInterceptors);
return response;
} catch (e) {
const response = {
return {
data: null,
error: e.response?.data ?? e.body,
};

updateResponseInterceptors(response, responseInterceptors);
return response;
}
};
15 changes: 3 additions & 12 deletions src/plugins/es_ui_shared/public/request/use_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,7 @@ export interface UseRequestResponse<D = any, E = Error> {

export const useRequest = <D = any, E = Error>(
httpClient: HttpSetup,
{
path,
method,
query,
body,
pollIntervalMs,
initialData,
deserializer,
responseInterceptors,
}: UseRequestConfig
{ path, method, query, body, pollIntervalMs, initialData, deserializer }: UseRequestConfig
): UseRequestResponse<D, E> => {
const isMounted = useRef(false);

Expand Down Expand Up @@ -89,7 +80,7 @@ export const useRequest = <D = any, E = Error>(
// 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 };
const response = await sendRequest<D, E>(httpClient, requestPayload);
const { data: serializedResponseData, error: responseError } = response;

Expand All @@ -115,7 +106,7 @@ export const useRequest = <D = any, E = Error>(
// 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]
);

const scheduleRequest = useCallback(() => {
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/upgrade_assistant/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ export const DEPRECATION_LOGS_SOURCE_ID = 'deprecation_logs';
export const DEPRECATION_LOGS_INDEX = '.logs-deprecation.elasticsearch-default';
export const DEPRECATION_LOGS_INDEX_PATTERN = '.logs-deprecation.elasticsearch-default';

export const CLUSTER_UPGRADE_STATUS_POLL_INTERVAL_MS = 45000;
export const CLOUD_BACKUP_STATUS_POLL_INTERVAL_MS = 60000;
export const DEPRECATION_LOGS_COUNT_POLL_INTERVAL_MS = 15000;
29 changes: 6 additions & 23 deletions x-pack/plugins/upgrade_assistant/public/application/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,30 @@ import { ScopedHistory } from 'src/core/public';

import { RedirectAppLinks } from '../../../../../src/plugins/kibana_react/public';
import { API_BASE_PATH } from '../../common/constants';
import { ClusterUpgradeState, ResponseError } from '../../common/types';
import { ClusterUpgradeState } from '../../common/types';
import { APP_WRAPPER_CLASS, GlobalFlyout, AuthorizationProvider } from '../shared_imports';
import { AppDependencies } from '../types';
import { AppContextProvider, useAppContext } from './app_context';
import { EsDeprecations, ComingSoonPrompt, KibanaDeprecations, Overview } from './components';

const { GlobalFlyoutProvider } = GlobalFlyout;

const isClusterUpgradeStateError = (error: ResponseError | null): boolean => {
return Boolean(error && error.statusCode === 426);
};

const App: React.FunctionComponent = () => {
const {
isReadOnlyMode,
services: { api },
} = useAppContext();

api.useClusterUpgradeStatus();

const [clusterUpgradeState, setClusterUpradeState] =
useState<ClusterUpgradeState>('isPreparingForUpgrade');

const handleClusterUpgradeStateError = useCallback(
(error: ResponseError | null) => {
if (error && error.attributes) {
setClusterUpradeState(
error.attributes.allNodesUpgraded ? 'isUpgradeComplete' : 'isUpgrading'
);
}
},
[setClusterUpradeState]
);

useEffect(() => {
api.addResponseInterceptor((response: ResponseError | null) => {
const { error } = response;
if (isClusterUpgradeStateError(error)) {
handleClusterUpgradeStateError(error);
}
return error;
api.onClusterUpgradeStateChange((newClusterUpgradeState: ClusterUpgradeState) => {
setClusterUpradeState(newClusterUpgradeState);
});
}, [api, handleClusterUpgradeStateError]);
}, [api, setClusterUpradeState]);

// Read-only mode will be enabled up until the last minor before the next major release
if (isReadOnlyMode) {
Expand Down
Loading

0 comments on commit 2f03b10

Please sign in to comment.