mirror of
https://github.com/valitydev/checkout.git
synced 2024-11-06 02:25:18 +00:00
TD-768: Restore fetch with retry (#245)
This commit is contained in:
parent
77151894df
commit
ec028279f7
@ -86,9 +86,16 @@ describe('fetch capi', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('should catch json reject', async () => {
|
||||
test('should retry json reject', async () => {
|
||||
const errorMsg = 'Read json error';
|
||||
const mockFetchJson = jest.fn().mockRejectedValueOnce(errorMsg);
|
||||
const expected = {
|
||||
someField: 'someValue',
|
||||
};
|
||||
const mockFetchJson = jest
|
||||
.fn()
|
||||
.mockRejectedValueOnce(errorMsg)
|
||||
.mockRejectedValueOnce(errorMsg)
|
||||
.mockResolvedValueOnce(expected);
|
||||
const mockFetch = jest.fn().mockResolvedValue({
|
||||
status: 200,
|
||||
ok: true,
|
||||
@ -99,10 +106,69 @@ describe('fetch capi', () => {
|
||||
const endpoint = 'https://api.test.com/endpoint';
|
||||
const accessToken = 'testToken';
|
||||
|
||||
const retryDelay = 50;
|
||||
const retryLimit = 10;
|
||||
|
||||
const result = await fetchCapi({ endpoint, accessToken }, retryDelay, retryLimit);
|
||||
expect(result).toStrictEqual(expected);
|
||||
expect(mockFetchJson).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
test('should retry failed fetch requests', async () => {
|
||||
const expected = {
|
||||
someField: 'someValue',
|
||||
};
|
||||
|
||||
const mockFetch = jest
|
||||
.fn()
|
||||
.mockRejectedValueOnce(new Error('TypeError: Failed to fetch'))
|
||||
.mockRejectedValueOnce(new Error('TypeError: Failed to fetch'))
|
||||
.mockResolvedValueOnce({
|
||||
status: 200,
|
||||
ok: true,
|
||||
json: async () => expected,
|
||||
});
|
||||
global.fetch = mockFetch;
|
||||
|
||||
const endpoint = 'https://api.test.com/endpoint';
|
||||
const accessToken = 'testToken';
|
||||
|
||||
const retryDelay = 50;
|
||||
const retryLimit = 10;
|
||||
|
||||
const result = await fetchCapi({ endpoint, accessToken }, retryDelay, retryLimit);
|
||||
|
||||
expect(result).toStrictEqual(expected);
|
||||
expect(mockFetch).toHaveBeenCalledTimes(3);
|
||||
const requestInit = {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
'X-Request-ID': expect.any(String),
|
||||
},
|
||||
method: 'GET',
|
||||
};
|
||||
expect(mockFetch).toHaveBeenCalledWith(endpoint, requestInit);
|
||||
expect(mockFetch).toHaveBeenCalledWith(endpoint, requestInit);
|
||||
expect(mockFetch).toHaveBeenCalledWith(endpoint, requestInit);
|
||||
});
|
||||
|
||||
test('should retry failed fetch requests based on config', async () => {
|
||||
const expectedError = new Error('TypeError: Failed to fetch');
|
||||
const mockFetch = jest.fn().mockRejectedValue(expectedError);
|
||||
global.fetch = mockFetch;
|
||||
|
||||
const endpoint = 'https://api.test.com/endpoint';
|
||||
const accessToken = 'testToken';
|
||||
|
||||
const retryDelay = 50;
|
||||
const retryLimit = 10;
|
||||
|
||||
try {
|
||||
await fetchCapi({ endpoint, accessToken });
|
||||
await fetchCapi({ endpoint, accessToken }, retryDelay, retryLimit);
|
||||
} catch (error) {
|
||||
expect(error).toStrictEqual(errorMsg);
|
||||
expect(error).toEqual(expectedError);
|
||||
}
|
||||
expect(mockFetch).toHaveBeenCalledTimes(retryLimit);
|
||||
});
|
||||
});
|
||||
|
@ -1,3 +1,4 @@
|
||||
import delay from 'checkout/utils/delay';
|
||||
import guid from 'checkout/utils/guid';
|
||||
|
||||
export type FetchCapiParams = {
|
||||
@ -15,8 +16,10 @@ const getDetails = async (response: Response) => {
|
||||
}
|
||||
};
|
||||
|
||||
const provideResponse = async (response: Response) => {
|
||||
const provideResponse = async (response: Response, retryDelay: number, retryLimit: number, attempt: number = 0) => {
|
||||
try {
|
||||
if (response.ok) {
|
||||
attempt++;
|
||||
return await response.json();
|
||||
}
|
||||
return Promise.reject({
|
||||
@ -24,10 +27,19 @@ const provideResponse = async (response: Response) => {
|
||||
statusText: response.statusText || undefined,
|
||||
details: await getDetails(response),
|
||||
});
|
||||
} catch (ex) {
|
||||
if (attempt === retryLimit) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
await delay(retryDelay);
|
||||
return provideResponse(response, retryDelay, retryLimit, attempt);
|
||||
}
|
||||
};
|
||||
|
||||
const doFetch = async (param: FetchCapiParams) =>
|
||||
fetch(param.endpoint, {
|
||||
const doFetch = async (param: FetchCapiParams, retryDelay: number, retryLimit: number, attempt: number = 0) => {
|
||||
try {
|
||||
attempt++;
|
||||
return await fetch(param.endpoint, {
|
||||
method: param.method || 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
@ -36,8 +48,16 @@ const doFetch = async (param: FetchCapiParams) =>
|
||||
},
|
||||
body: param.body ? JSON.stringify(param.body) : undefined,
|
||||
});
|
||||
|
||||
export const fetchCapi = async <T>(param: FetchCapiParams): Promise<T> => {
|
||||
const response = await doFetch(param);
|
||||
return await provideResponse(response);
|
||||
} catch (ex) {
|
||||
if (attempt === retryLimit) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
await delay(retryDelay);
|
||||
return doFetch(param, retryDelay, retryLimit, attempt);
|
||||
}
|
||||
};
|
||||
|
||||
export const fetchCapi = async <T>(param: FetchCapiParams, retryDelay = 3000, retryLimit = 10): Promise<T> => {
|
||||
const response = await doFetch(param, retryDelay, retryLimit);
|
||||
return await provideResponse(response, retryDelay, retryLimit);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user