
Security News
The Changelog Podcast: Practical Steps to Stay Safe on npm
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.
@adeira/fetch
Advanced tools
Production ready fetch function with advanced capabilities like retries with delay and request cancellation after timeout.
This package has been extracted from the original fbjs library, and it exposes single fetchWithRetries function. This function is only a wrapper for any other well known fetch API. However, this fetch also solves these common problems:
This makes the fetch function more suitable for real-life production usage because it doesn't hang or fail easily. In other words you are not going to have many open connections just because the API is slow (this could kill your server completely) and your fetch won't give up if the API didn't respond for the first time (just some glitch and one retry would fix it).
yarn add @adeira/fetch
This fetch is basically drop-in replacement for any other fetch you use:
import fetch from '@adeira/fetch';
(async () => {
const response = await fetch('https://api.skypicker.com/locations?term=Barcelona');
console.log(await response.json());
})();
There are however some interesting features on top of this API. You can for example change the internal timings:
import fetchWithRetries from '@adeira/fetch';
(async () => {
try {
const response = await fetchWithRetries(
'https://cs-api.skypicker.com/public/numbers?country_code=er404', // this returns 404
{
fetchTimeout: 15000, // ms
retryDelays: [1000, 3000], // ms
// ...
// see https://github.com/github/fetch/ for more options (headers, method, body, ...)
},
);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error.response);
console.error(error.response.status); // 404
console.error(error.response.statusText); // NOT FOUND
const response = await error.response.json();
console.error(response); // { message: 'provided country_code does not exist', status: 'error' }
}
})();
It does two things:
Retries are performed in these situations:
fetchTimeout) occursThis package uses fetch ponyfill internally (cross-fetch) so it supports server JS as well as browsers and React Native environment. It will always try to use global fetch if available before using this ponyfill.
You have to catch errors while fetching the response. This fetch throws these exceptions:
Error) when request failed for some reasonTimeoutError when fetch fails because of defined timeoutResponseError when final response returns HTTP status <200 or >=300Example:
import fetchWithRetries, { TimeoutError, ResponseError } from '@adeira/fetch';
(async () => {
try {
const response = await fetchWithRetries('//localhost');
const data = await response.json();
console.log(data);
} catch (error) {
if (error instanceof TimeoutError) {
console.error('request timeouted');
} else if (error instanceof ResponseError) {
console.error('unsuccessful response', error.response);
} else {
console.error('unknown error');
}
}
})();
You can easily cancel any request via AbortController (https://developer.mozilla.org/en-US/docs/Web/API/AbortController) like so:
const controller = new AbortController();
const signal = controller.signal;
const response = await fetchWithRetries('//localhost', {
signal,
});
// You can cancel it somewhere from your code when needed (Relay network cleanup for example).
controller.abort();
Let's have a look at this config:
const config = {
fetchTimeout: 2000,
retryDelays: [100, 3000],
};
There are many situations that may occur (skipping happy path):
Example with timeouts:
In reality, you can see some more optimistic scenarios: for example request failed with HTTP status code 500 and it's resolved immediately after you retry it (just some API glitch). Similar scenarios are quite often for timeouts: first try timeouted for some reason but it's OK when you try for the second time.
One way how to mock this fetch is to use manual mock (src/__mocks__/@adeira/fetch.js):
export default function fetchWithRetriesMock(resource: string) {
return Promise.resolve(`MODIFIED ${resource.toUpperCase()} 1`);
}
And then just use it:
import fetchWithRetriesMock from '@adeira/fetch';
jest.mock('@adeira/fetch');
it('mocks the fetch', async () => {
await expect(fetchWithRetriesMock('input')).resolves.toBe('MODIFIED INPUT 1');
});
Alternatively, you could inline the mock:
import fetchWithRetriesMock from '@adeira/fetch';
jest.mock('@adeira/fetch', () => {
return (resource) => Promise.resolve(`MODIFIED ${resource.toUpperCase()} 2`);
});
it('mocks the fetch', async () => {
await expect(fetchWithRetriesMock('input')).resolves.toBe('MODIFIED INPUT 2');
});
Why mocking global.fetch doesn't work? It's because this fetch doesn't use or pollute global variable: it uses ponyfill instead of polyfill behind the scenes.
There is an alternative to mocking the fetch function. You can use msw What it does is start a service worker (yes it works in node as well) and that service worker stops the network request and returns mocked data.
"I found MSW and was thrilled that not only could I still see the mocked responses in my DevTools, but that the mocks didn't have to be written in a Service Worker and could instead live alongside the rest of my app. This made it silly easy to adopt. The fact that I can use it for testing as well makes MSW a huge productivity booster."
– Kent C. Dodds
FAQs
Production ready fetch function with advanced capabilities like retries with delay and request cancellation after timeout.
The npm package @adeira/fetch receives a total of 81 weekly downloads. As such, @adeira/fetch popularity was classified as not popular.
We found that @adeira/fetch demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.

Security News
Experts push back on new claims about AI-driven ransomware, warning that hype and sponsored research are distorting how the threat is understood.

Security News
Ruby's creator Matz assumes control of RubyGems and Bundler repositories while former maintainers agree to step back and transfer all rights to end the dispute.