JavaScript library that handles network corner cases.
Handli aims to bring sensible defaults to questions like: When the user goes offline, what should happen with the UI?
It is customizable and progressively removable so that you can quickly ship a prototype and later progressively replace Handli with your own handling.
Contents
Usage
$ npm install handli
import handli from 'handli';
Then simply wrap your requests with handli
:
-const response = await fetch(url);
+const response = await handli(() => fetch(url));
That's it. All network corner cases are now handled by Handli.
How it Works
The handli
function never rejects and resolves only when it gets a successful response from the server.
That is:
import handli from 'handli';
let response;
try {
response = await handli(() => fetch('https://example.org'));
} catch(_) {
// `handli` never rejects
assert(false);
}
// `handli` only resolves successful responses
assert(200<=response.status && response.status<=299);
If the server doesn't reply a 2xx
,
then Handli blocks the UI,
shows a modal letting the user know what's going on,
and periodically retries the request.
You can write code as if network issues are non-existent and rely upon Handli for handling errors.
You can also handle errors yourself and Handli will skip these handled errors.
FAQ
Can I customize the UI?
Yes. See Live Demo - Custom Style and Live Demo - Custom UI.
Can I customize the texts?
Yes. See Live Demo - Custom Text.
What if a non-2xx server reply is expected and I don't want Handli to treat it as error?
Then handle the error yourself, see below.
How do I handle errors myself?
Handle errors within your request function.
For example, if you want to handle an API rate limit:
const RATE_LIMIT = Symbol();
const response = await fetch(async () => {
const response = await (
fetch('https://api.example.org/project/42')
);
if( response.status===429 ) {
return RATE_LIMIT;
} else {
return response;
}
});
if( response===RATE_LIMIT ) {
// Code that handles reached API rate limit
} else {
assert(200<=response.status && response.status<=299);
}
See Live Demo - Handled Error.
When is the user's internet connection considered slow?
If a request isn't getting a response, then Handli tests the user's internet connection. To do so, Handli pings Google, Facebook, Cloudflare, and Amazon.
If the fastest ping is higher than thresholdSlowInternet
then
Handli considers the connection as slow.
If none of the ping requests get a response after thresholdNoInternet
then Handli
considers the user offline.
By default thresholdSlowInternet
is 500
milliseconds and thresholdNoInternet
is 900
milliseconds.
The Live Demo - Custom Slow Threshold shows how to change these defaults.
Note that Handli handles slow connections only if you provide a timeout
:
// Handli will show a UI-blocking modal if there is no response after 2 seconds
handli.timeout = 2000;
const response = await handli(
() => fetch(url),
);
If you don't provide a timeout
then
Handli indefinitely waits for a response
without showing the UI-blocking modal.
Alternatively to timeout
, you can provide timeoutInternet
and/or timeoutServer
:
- If the user's internet connection is slow and
if a request doesn't get a response after
timeoutInternet
, then Handli shows the UI-blocking modal. - If the user's internet connection isn't slow and
if a request doesn't get a response after
timeoutServer
, then Handli shows the UI-blocking modal.
See Live Demo - Slow Internet and Live Demo - Unresponsive Server.
fetch
?
Does it only work with Handli works with any fetch-like library. That is, Handli works as long as:
-
response.status
holds the status code of the response. (Withresponse
we meanlet response = await aFetchLikeLibrary('https://example.org')
.) -
response.ok
holdstrue
orfalse
denoting whether the request was a success. (That isassert(response.ok === 200<=response.status && response.status<=299)
.) - Throws if and only if the request didn't get a response. (That is if the user has internet connection problems or if the server is not responsive.)
Does it handle errors on Node.js?
No. Handli handles the network only in the browser.
What about Universal/Isomorphic/SSR?
Handli supports code that are run in the browser and on Node.js.
When run in Node.js, handli
is transparent:
It does nothing and returns what your request function returns.
On Node.js, the following
const response = await handli(() => fetch(url));
is equivalent to
const response = await fetch(url);
Does it support simultaneous requests?
Yes. Handli blocks the UI until all requests get a successful response (or a handled error.)