Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(fetch): cache strategy #340

Merged
merged 11 commits into from
Oct 21, 2022
23 changes: 18 additions & 5 deletions demo/fetch/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,26 @@
</head>

<body>
<h3>Check the console</h3>

<h1>@alwatr/fetch</h1>

<label for="cacheSelect">Cache Strategy:</label>
<select name="caches" id="cacheSelect">
<option value="network_only">Network Only</option>
<option value="network_first">Network First</option>
<option value="cache_only">Cache Only</option>
<option value="cache_first">Cache First</option>
<option value="stale_while_revalidate">Stale While Revalidate</option>
</select>


<div class="buttons">
<button class="success" data-url="https://httpbin.org/status/200">200 Response</button>
<button class="success" data-url="https://httpbin.org/delay/1">1s Delay</button>
<button class="fail" data-url="https://httpbin.org/status/503">503 Response</button>
<button class="fail" data-url="https://httpbin.org/delay/5">5s Delay</button>
<button class="success" data-url="//httpbin.org/status/200">200 Response</button>
<button class="success" data-url="//httpbin.org/delay/1">1s Delay</button>
<button class="fail" data-url="//httpbin.org/status/503">503 Response</button>
<button class="fail" data-url="//httpbin.org/delay/5">5s Delay</button>
</div>

<h3>Check the console for result</h3>
</body>
</html>
19 changes: 14 additions & 5 deletions demo/fetch/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import {fetch} from '@alwatr/fetch';

import type {CacheStrategy} from '@alwatr/fetch';

const buttons = document.querySelectorAll('button') as NodeListOf<HTMLButtonElement>;

for (const button of buttons) {
const buttonURL = button.dataset.url;
const url = button.dataset.url;

if (button && buttonURL) {
if (button && url) {
button.addEventListener('click', async () => {
if (button.classList.contains('loading')) return;

button.classList.add('loading');
try {
const response = await fetch(buttonURL);
console.log('%s | %O', buttonURL, response);
const response = await fetch({
url,
timeout: 2000,
retry: 2,
mode: 'cors',
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
cacheStrategy: document.querySelector<HTMLSelectElement>('#cacheSelect')!.value as CacheStrategy,

Check warning

Code scanning / ESLint

Disallow non-null assertions using the `!` postfix operator

Forbidden non-null assertion.
});
console.log('Demo response: %o', {url, response, text: await response.text()});
}
catch (error) {
console.error('%s | %O', buttonURL, error);
console.warn('Demo catch error: %o', {url, error});
}
button.classList.remove('loading');
});
Expand Down
1 change: 1 addition & 0 deletions demo/fetch/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
gap: 24px;
padding: 24px;
}

button {
display: flex;
align-items: center;
Expand Down
68 changes: 41 additions & 27 deletions packages/core/fetch/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
# @alwatr/fetch

Enhanced fetch API with the timeout, helper methods, and types written in tiny TypeScript, ES module.

## Options

`Options` inherited from the `RequestInit`. you can watch all documents of the parameters RequestInit in [`fetch init parameters`](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters)

Options have some other parameters:

- `bodyJson`: a JSON object that converts to string and put on the body.
- `queryParameters`: a JSON object that converts to URL query params.
- `timeout`: A timeout for the fetch request.
- `retry` If fetch response not acceptable or timed out, it will retry the request
Enhanced fetch API with cache strategy, retry pattern, timeout, helper methods and enhanced types written in tiny TypeScript, ES module.

## Example usage

Expand All @@ -25,35 +14,60 @@ interface ProductInterface {
image: string;
}

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

## API
## Fetch Options

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

It's a wrapper around the browser's `fetch` function that adds retry pattern with timeout
- `url`: Request URL.
- `bodyJson`: Body as JS Object.
- `queryParameters`: URL Query Parameters as JS Object.
- `timeout`: A timeout in ms for the fetch request (default `5000`ms).
- `retry`: If fetch response not acceptable or timed out, it will retry the request (default `3`).
- `cacheStorageName`: Cache storage name (default `alwatr_fetch_cache`).
- `cacheStrategy`: Strategies for caching, (default `network_only`).
- `network_only`: Only network request without any cache.
- `network_first`: Network first, falling back to cache.
- `cache_only`: Cache only without any network request.
- `cache_first`: Cache first, falling back to network.
- `stale_while_revalidate`: Fastest strategy, Use cached first but always request network to update the cache.

```ts
await fetch(url, {timeout: 5_000, bodyJson: {a: 1, b: 2}});
```
[Read more about standard cache strategies](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#caching-strategies)

### `getJson(url: string, options: FetchOptions = {})`
## API

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

It fetches a JSON file from a URL, and returns the JSON data
It's a wrapper around the browser's `fetch` function that adds retry pattern with timeout and cacheStrategy.

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

### `postJson(url: string, bodyJson: Record<string | number, unknown>, options?: FetchOptions)`
### `getJson<T>(options: FetchOptions): Promise<T>`

It takes a URL, a JSON object, and an optional FetchOptions object, and returns a Promise of a Response object
It fetches a JSON file from a URL, and returns the parsed data.

```ts
await postJson(url, {first_name: 'foo', last_name: 'bar'});
const productList = await getJson<ProductResponse>({
url: '/api/products',
queryParameters: {limit: 10},
timeout: 5_000,
retry: 3,
cacheStrategy: 'stale_while_revalidate',
});
```
4 changes: 3 additions & 1 deletion packages/core/fetch/package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"name": "@alwatr/fetch",
"version": "0.17.0",
"description": "Enhanced fetch api with timeout, helper methods and types written in tiny TypeScript module.",
"description": "Enhanced fetch API with cache strategy, retry pattern, timeout, helper methods and enhanced types written in tiny TypeScript, ES module.",
"keywords": [
"fetch",
"request",
"api",
"retry",
"cache",
"timeout",
"typescript",
"esm",
Expand Down
Loading