This repository was archived by the owner on Jan 29, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfetcher.ts
More file actions
95 lines (78 loc) · 2.23 KB
/
fetcher.ts
File metadata and controls
95 lines (78 loc) · 2.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { makeRequestParams } from './make-request-params'
import safeParseJson from './safe-parse-json'
import { HttpMethods, HttpResponse, RequestOptions } from './types'
export async function fetcher<SuccessBody, FailureBody = unknown>(
url: string,
options: RequestOptions,
): Promise<HttpResponse<SuccessBody, FailureBody>> {
const { retryable, method = HttpMethods.Get } = options
const fetchFunction =
method === HttpMethods.Get && retryable
? makeFetchRetryable({
fetch,
retryCount: 3,
})
: fetch
const response = await fetchFunction(...makeRequestParams(url, options))
const body = await readResponseBody(response)
const { headers, status, url: responseUrl } = response
if (response.ok === true) {
return {
headers,
status,
url: responseUrl,
ok: true,
parsedBody: body as SuccessBody,
}
}
return {
headers,
status,
url: responseUrl,
ok: false,
parsedBody: body as FailureBody,
}
}
const refetchStatuses = [502, 503, 504]
function makeFetchRetryable({
fetch,
retryCount,
}: {
fetch: (href: string, requestInit?: RequestInit) => Promise<Response>
retryCount: number
}) {
function isRetryable({
response,
remainRetry,
}: {
response: Response
remainRetry: number
}): boolean {
return remainRetry > 0 && refetchStatuses.includes(response.status)
}
return function retryableFetch(
href: string,
requestInit?: RequestInit,
): Promise<Response> {
async function retryer(remainRetry: number): Promise<Response> {
const response = await fetch(href, requestInit)
if (isRetryable({ response, remainRetry }) === false) {
return response
}
const jitterDelay = Math.random() + 1
await new Promise((resolve) =>
setTimeout(resolve, 100 * (Math.pow(2, 3 - remainRetry) + jitterDelay)),
)
return retryer(remainRetry - 1)
}
return retryer(retryCount)
}
}
export function readResponseBody(response: Response) {
const contentType = response.headers.get('content-type')
const jsonParseAvailable = contentType && /json/.test(contentType)
if (jsonParseAvailable) {
return safeParseJson(response)
}
return response.text()
}