Skip to content

Commit

Permalink
Merge pull request #400 from AliMD/feat/fetch
Browse files Browse the repository at this point in the history
refactor(fetch): remove getJson
  • Loading branch information
alimd authored Nov 16, 2022
2 parents 161173c + 3798c41 commit 6c652cc
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 101 deletions.
19 changes: 12 additions & 7 deletions demo/fetch/node.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import {fetch} from '@alwatr/fetch';

const response = await fetch({
url: 'http://httpbin.org/uuid',
timeout: 3_000,
removeDuplicate: 'auto',
});

console.log(await response.text());
try {
const response = await fetch({
url: 'http://httpbin.org/uuid',
timeout: 3_000,
removeDuplicate: 'auto',
});
console.log('ok: %s', response.ok);
console.log('text: %s', await response.text());
}
catch (err) {
console.error(err);
}
53 changes: 13 additions & 40 deletions packages/core/fetch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,29 @@ Enhanced fetch API with cache strategy, retry pattern, timeout, helper methods a

## Example usage

```ts
import {getJson} from 'https://esm.run/@alwatr/fetch';
### `fetch(options: FetchOptions): Promise<Response>`

interface ProductInterface {
_id: string;
name: string;
description: string;
image: string;
}
It's a wrapper around the browser's `fetch` function that adds retry pattern with timeout and cacheStrategy.

```ts
import {fetch} from 'https://esm.run/@alwatr/fetch';

const productList = await getJson<Record<string, ProductInterface>>({
const response = await fetch({
url: '/api/products',
queryParameters: {limit: 10},
timeout: 5_000,
retry: 3,
cacheStrategy: 'stale_while_revalidate',
});

if (!response.ok) throw new Error('fetch_failed');

const productList = await response.json();

console.log(productList);
```

## Fetch Options
### Fetch Options

`FetchOptions` inherited from the [fetch standard parameters](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) and some other...

Expand All @@ -48,33 +51,3 @@ const productList = await getJson<Record<string, ProductInterface>>({
- `cacheStorageName`: Cache storage custom name (default `alwatr_fetch_cache`).

[Read more about standard cache strategies](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#caching-strategies)

## API

### `fetch(options: FetchOptions): Promise<Response>`

It's a wrapper around the browser's `fetch` function that adds retry pattern with timeout and cacheStrategy.

```ts
const response = await fetch({
url: '/api/products',
queryParameters: {limit: 10},
timeout: 5_000,
retry: 3,
cacheStrategy: 'stale_while_revalidate',
});
```

### `getJson<T>(options: FetchOptions): Promise<T>`

It fetches a JSON file from a URL, and returns the parsed data.

```ts
const productList = await getJson<ProductResponse>({
url: '/api/products',
queryParameters: {limit: 10},
timeout: 5_000,
retry: 3,
cacheStrategy: 'stale_while_revalidate',
});
```
51 changes: 1 addition & 50 deletions packages/core/fetch/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,55 +93,6 @@ const cacheSupported = 'caches' in globalThis;

const duplicateRequestStorage: Record<string, Promise<Response>> = {};

/**
* It fetches a JSON file from a URL, and returns the parsed data.
*
* Example:
*
* ```ts
* const productList = await getJson<ProductResponse>({
* url: '/api/products',
* queryParameters: {limit: 10},
* timeout: 10_000,
* retry: 3,
* cacheStrategy: 'stale_while_revalidate',
* cacheDuplicate: 'auto',
* });
* ```
*/
export async function getJson<ResponseType extends Record<string | number, unknown>>(
_options: Partial<FetchOptions> & {url: string},
): Promise<ResponseType> {
const options = _processOptions(_options);
logger.logMethodArgs('getJson', {options});

const response = await _handleRemoveDuplicate(options);

let data: ResponseType;

try {
if (!response.ok) {
throw new Error('fetch_nok');
}
data = (await response.json()) as ResponseType;
}
catch (err) {
logger.accident('getJson', 'response_json', 'response json error', {
retry: options.retry,
err,
});

if (options.retry > 1) {
data = await getJson(options);
}
else {
throw err;
}
}

return data;
}

/**
* It's a wrapper around the browser's `fetch` function that adds retry pattern, timeout, cacheStrategy,
* remove duplicates, etc.
Expand Down Expand Up @@ -332,7 +283,7 @@ async function _handleRetryPattern(options: FetchOptions): Promise<Response> {
options.retry--;
options.signal = externalAbortSignal;
await _wait(options.retryDelay);
return _handleCacheStrategy(options); // maybe cache updated by another request ;)
return _handleRetryPattern(options);
};

try {
Expand Down
27 changes: 23 additions & 4 deletions packages/core/i18n/src/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {getJson} from '@alwatr/fetch';
import {fetch} from '@alwatr/fetch';
import {alwatrRegisteredList, createLogger} from '@alwatr/logger';
import {SignalInterface} from '@alwatr/signal';

Expand Down Expand Up @@ -112,9 +112,28 @@ l10n.resourceChangeSignal.setProvider(async (locale) => {
return;
}

return await getJson<L10Resource>({url: `${l10n.config.resourcePath}/${locale.code}.json`});
// TODO: cache requests using fetch (add feature for fetch)
// TODO: catch errors and fallback
const url = `${l10n.config.resourcePath}/${locale.code}.json`;
try {
const response = await fetch({
url,
retry: 20,
retryDelay: 1_000,
timeout: 10_000,
removeDuplicate: 'auto',
cacheStrategy: 'stale_while_revalidate',
});

if (response.ok) {
return response.json();
}
else {
throw new Error('fetch_nok');
}
}
catch (err) {
logger.error('resourceProvider', 'fetch_failed', (err as Error).stack || err, {locale, url});
// TODO: user error signal.
}
});

/**
Expand Down

0 comments on commit 6c652cc

Please sign in to comment.