Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/helmturner/fetch-again
Fetch, but with configurable retries
https://github.com/helmturner/fetch-again
Last synced: 24 days ago
JSON representation
Fetch, but with configurable retries
- Host: GitHub
- URL: https://github.com/helmturner/fetch-again
- Owner: helmturner
- Created: 2023-02-04T07:27:41.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-08-19T16:19:46.000Z (about 1 year ago)
- Last Synced: 2024-10-04T16:22:03.635Z (about 1 month ago)
- Language: TypeScript
- Homepage:
- Size: 299 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# fetch-again
[![npm version](https://badge.fury.io/js/fetch-again.svg)](https://badge.fury.io/js/fetch-again)
A tiny, dependency-free TS library for adding retry logic to your favorite fetch implementation.
## HERE BE DRAGONS
This library is not intended for production use.
## Installation
Using npm:
```bash
npm install @helmturner/fetch-again
```Using yarn:
```bash
yarn add @helmturner/fetch-again
```## Usage
```typescript
import fetchWithRetry from "@helmturner/fetch-again";const response = await fetchWithRetry(options, "https://example.com", {
method: "POST",
body: JSON.stringify({ foo: "bar" }),
});
```## API
### `fetchWithRetry(options, ...fetchArguments)` -> `Promise` | `Promise`
#### `options`
##### `fetchFn` (optional)
A fetch implementation to use. If not provided, the library will attempt to find a fetch implementation in the following order:
1. `fetch` (global)
2. `window.fetch` (browser)
3. `global.fetch` (node)
4. `require("node-fetch")` (must be installed as a dependency)##### `retries` (optional)
The number of times to retry the request. Defaults to `3`.
##### `factor` (optional)
The exponential factor to use. Defaults to `2`. The timeout between retries will grow by this factor between each retry, e.g. for a factor of `2` the timeout will double with each retry.
##### `minTimeout` (optional)
The minimum timeout between retries, in milliseconds. Defaults to `1000`.
##### `maxTimeout` (optional)
The maximum timeout between retries, in milliseconds. Defaults to `10000`.
##### `randomize` (optional)
Whether to randomize the timeout between retries. Defaults to `false`.
##### `onRetry` (optional)
A callback to be called after each retry. The callback will be passed the result of the request (regardless of whether returned or thrown) and the number of retries remaining. Defaults to a no-op.
##### `retryOn` (optional)
A function that determines whether to retry the request. The function will be passed the result of the request (regardless of whether it was returned or thrown) and the number of retries remaining.
By default, the following steps are taken to determine whether to retry:
1. If the number of retries remaining is `0`, the request will not be retried.
2. If the result is an instance of `Error` or `null`, the request will be retried.
3. If the result has an `ok` property, the request will only be retried if the value of `ok` is **falsey**
4. Otherwise, If the result has any property that is a number between `100` and `599` inclusive, the request will be retried only if the value of that property is `408`, `413`, `429`, `500`, `502`, `503` or `504`.
5. If none of the above conditions are met, an error will be thrown.**_IT IS HIGHLY RECOMMENDED THAT YOU PROVIDE A CUSTOM `retryOn` FUNCTION IF USING A FETCH IMPLEMENTATION OTHER THAN `node-fetch` OR THE `fetch` API_**
#### `...fetchArguments`
The arguments to pass to the fetch implementation. The arguments should be the same as the arguments you would pass to the fetch implementation you are using - TypeScript will type them according to the fetch function passed.
## Examples
With default `fetch` implementation:
```typescript
import fetchWithRetry from "@helmturner/fetch-again";const options = {
retries: 5,
factor: 2,
minTimeout: 1000,
maxTimeout: 10000,
randomize: true,
onRetry: (result, count) => {
console.log(`Retrying request. ${count} retries remaining.`);
},
retryOn: (result, count) => {
if (count === 0) return false;
if (result instanceof Error) return true;
if (result.status === 429) return true;
return false;
},
};const response = await fetchWithRetry(options, "https://example.com", {
method: "POST",
body: JSON.stringify({ foo: "bar" }),
});
```With custom `fetch` implementation:
```typescript
import fetchWithRetry from "@helmturner/fetch-again";
import axios from "axios";const options = {
fetchFn: axios,
retries: 5,
factor: 2,
minTimeout: 1000,
maxTimeout: 10000,
randomize: true,
onRetry: (result, count) => {
console.log(`Retrying request. ${count} retries remaining.`);
},
retryOn: (result, count) => {
if (count === 0) return false;
if (error.response && typeof error.response.status === "number") {
return [408, 413, 429, 500, 502, 503, 504].includes(
error.response.status
);
}
return true;
},
};const response = await fetchWithRetry(options, {
url: "https://example.com",
method: "get",
});
```## License
ISC License (ISC)
Copyright (c) 2023 Helm Turner