Supertiny (4kB minified & 0 dependencies) and strong-typed HTTP client for Deno, Bun, Node.js, Cloudflare Workers and Browsers.
# Node.js
npm install hypf
# Bun
bun install hypf
The idea of this tool is to provide lightweight fetch
wrapper for Node.js, Bun:
import hypf from "hypf";
const hypfRequest = hypf.createRequest("https://jsonplaceholder.typicode.com"); // Pass true for DEBUG mode
// Example usage of POST method with retry and timeout
const [postErr, postData] = await hypfRequest.post(
"/posts",
{ retries: 3, timeout: 5000 },
{
title: "foo",
body: "bar",
userId: 1,
}
);
if (postErr) {
console.error("POST Error:", postErr);
} else {
console.log("POST Data:", postData);
}
Cloudflare Workers:
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
const hypfInstance = await hypf.createRequest(
"https://jsonplaceholder.typicode.com"
);
const [getErr, getData] = await hypfInstance.get<
Array<{
userId: number;
id: number;
title: string;
body: string;
}>
>("/posts");
if (getErr) {
console.error("GET Error:", getErr);
}
return Response.json(getData);
},
};
and Browsers:
<script src="https://unpkg.com/hypf/dist/hyperfetch-browser.min.js"></script>
<script>
(async () => {
const request = hypf.default.createRequest(
"https://jsonplaceholder.typicode.com"
);
})();
</script>
We define things easier with composed functions, ofcourse contribute easier.
get: (url, options, data) => httpMethodFunction(url, options)('GET', options, data),
post: (url, options, data) => httpMethodFunction(url, options)('POST', options, data),
put: (url, options, data) => httpMethodFunction(url, options)('PUT', options, data),
delete: (url, options, data) => httpMethodFunction(url, options)('DELETE', options, data),
patch: (url, options, data) => httpMethodFunction(url, options)('PATCH', options, data),
options: (url, options, data) => httpMethodFunction(url, options)('OPTIONS', options, data),
getAbortController,
No need to write try..catch
! hypf do it like this:
const hypfRequest = hypf.createRequest("https://jsonplaceholder.typicode.com";
// Example usage of POST method with retry and timeout
const [postErr, postData] = await hypfRequest.post(
'/posts',
{ retries: 3, timeout: 5000 },
{
title: 'foo',
body: 'bar',
userId: 1,
}
);
if (postErr) {
console.error('POST Error:', postErr);
} else {
console.log('POST Data:', postData);
}
Hooks is supported and expected to not modifying the original result by design.
const hooks = {
preRequest: (url, options) => {
console.log(`Preparing to send request to: ${url}`);
// You can perform actions before the request here
},
postRequest: (url, options, data, response) => {
console.log(
`Request to ${url} completed with status: ${
response?.[0] ? "error" : "success"
}`
);
// You can perform actions after the request here, including handling errors
},
};
const requestWithHooks = hypf.createRequest(
"https://jsonplaceholder.typicode.com",
hooks,
true
); // pass true for DEBUG mode
// Example usage of POST method with retry and timeout
const [postErr, postData] = await requestWithHooks.post(
"/posts",
{ retries: 3, timeout: 5000 },
{
title: "foo",
body: "bar",
userId: 1,
}
);
List of Hooks:
export interface Hooks {
preRequest?: (url: string, options: RequestOptions) => void;
postRequest?: <T, U>(
url: string,
options: RequestOptions,
data?: T,
response?: [Error | null, U]
) => void;
preRetry?: (
url: string,
options: RequestOptions,
retryCount: number,
retryLeft: number
) => void;
postRetry?: <T, U>(
url: string,
options: RequestOptions,
data?: T,
response?: [Error | null, U],
retryCount?: number,
retryLeft?: number
) => void;
preTimeout?: (url: string, options: RequestOptions) => void;
postTimeout?: (url: string, options: RequestOptions) => void;
}
You can retry your request once it's failed!
const [postErr, postData] = await requestWithHooks.post(
"/posts",
{ retries: 3, timeout: 5000 },
{
title: "foo",
body: "bar",
userId: 1,
}
);
Jitter and backoff also supported. π
const [postErr, postData] = await requestWithHooks.post(
"/posts",
{ retries: 3, timeout: 5000, jitter: true }, // false `jitter` to use backoff
{
title: "foo",
body: "bar",
userId: 1,
}
);
You can modify backoff and jitter factor as well.
const [postErr, postData] = await requestWithHooks.post(
"/posts",
{ retries: 3, timeout: 5000, jitter: true, jitterFactor: 10000 }, // false `jitter` to use backoff
{
title: "foo",
body: "bar",
userId: 1,
}
);
// or backoff
const [postErr, postData] = await requestWithHooks.post(
"/posts",
{ retries: 3, timeout: 5000, jitter: false, backoffFactor: 10000 }, // false `jitter` to use backoff
{
title: "foo",
body: "bar",
userId: 1,
}
);
Retry on timeout also supported.
const [postErr, postData] = await requestWithHooks.post(
"/posts",
{ retries: 3, timeout: 5000, retryOnTimeout: true },
{
title: "foo",
body: "bar",
userId: 1,
}
);
const [getErr, getData] = await hypfRequest.get<
Array<{
userId: number;
id: number;
title: string;
body: string;
}>
>("/posts", {
retries: 3,
timeout: 5000,
});
getData?.[0]?.id; // number | undefined
const [getErr, getData] = await hypfRequest.get("/posts", {
retries: 3,
timeout: 5000,
params: {
id: 1,
},
}); // /posts?id=1
const DEFAULT_MAX_TIMEOUT = 2147483647;
const DEFAULT_BACKOFF_FACTOR = 0.3;
const DEFAULT_JITTER_FACTOR = 1;
We expose abort controller, you can cancel next request anytime.
// DELETE will not work if you uncomment this
const controller = requestWithHooks.getAbortController();
controller.abort();
// Example usage of DELETE method with retry and timeout
const [deleteErr, deleteData] = await requestWithHooks.delete("/posts/1", {
retries: 3,
timeout: 5000,
});
if (deleteErr) {
console.error("DELETE Error:", deleteErr);
} else {
console.log("DELETE Data:", deleteData);
}
License MIT 2024