1 | import unfetch from 'isomorphic-unfetch';
|
2 | import lru from 'tiny-lru';
|
3 | import { FetchError } from './errors';
|
4 | import { log } from './log';
|
5 |
|
6 | const maxItems = 250;
|
7 | const fiveMinutesTTL = 5 * 60 * 1000;
|
8 | const cache = lru(maxItems, fiveMinutesTTL);
|
9 |
|
10 | export async function fetch({
|
11 | url,
|
12 | headers,
|
13 | cached = true,
|
14 | }: {
|
15 | url: string;
|
16 | headers?: Record<string, string>;
|
17 | cached?: boolean;
|
18 | }): Promise<any> {
|
19 | const cacheKey = `headers=${JSON.stringify(headers)};url=${url}`;
|
20 | const cachedJSON = cache.get(cacheKey);
|
21 | if (cached && cachedJSON) {
|
22 | log('fetch: returning cached response: %O', {
|
23 | cacheKey,
|
24 | url,
|
25 | cachedJSON,
|
26 | });
|
27 | return cachedJSON;
|
28 | }
|
29 |
|
30 | const response = await unfetch(url, { headers });
|
31 | if (!response.ok) {
|
32 | log('fetch: request failed: %O', {
|
33 | url,
|
34 | headers,
|
35 | status: response.statusText,
|
36 | response,
|
37 | });
|
38 | throw new FetchError(url, response);
|
39 | }
|
40 |
|
41 | const json = await response.json();
|
42 | if (cached) {
|
43 | cache.set(cacheKey, json);
|
44 | }
|
45 |
|
46 | log('fetch: returning fresh response: %O', { url, json });
|
47 | return json;
|
48 | }
|