Small (7.2kB minified & 0 dependencies) and type-powered HTTP client for Deno, Bun, Node.js, Cloudflare Workers and Browsers. π
The most flexible fetch wrapper that allows you to have more than one practice to get things done!
- Get Started
- Error Handling
- Response Cloning
- Request Cloning & Dry Run
- Hooks
- Retry Mechanism
- Infer Response Types
- URLSearchParams
- Form Data
- AbortController
- Debug
- Acknowledgements
- License
# 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.init('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)
}
Cloudflare Workers:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const hypfInstance = await hypf.init('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/browser/hyperfetch-browser.min.js"></script>
<script>
;(async () => {
const request = hypf.default.init('https://jsonplaceholder.typicode.com')
})()
</script>
You can handle errors like Error handling on Golang
const hypfRequest = hypf.init('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)
}
or since v0.2.2
throw on error with throwOnError
options sets true
const hypfRequest = hypf.init('https://jsonplaceholder.typicode.com')
try {
const response = await hypfRequest.post(
'/posts',
{ retries: 3, timeout: 5000, initOptions: { throwOnError: true } },
{
title: 'foo',
body: 'bar',
userId: 1,
}
)
console.log(response)
} catch (err) {
console.log(err)
}
You need to use throwOnError: true
to enable Response clone feature.
const res = await hypfRequest.get(
'https://jsonplaceholder.typicode.com/todos/1',
{},
{},
{
throwOnError: true,
}
)
const res2 = res.clone()
console.log(res2)
Dry Run is supported in hypf, you can calling hypf requests without executing it!
This enables more features in the future and also Request cloning:
const req = await hypfRequest.get(
'https://jsonplaceholder.typicode.com/todos/1',
{
dryRun: true,
},
{},
{
throwOnError: true,
}
)
const req2 = req.clone()
console.log(req2)
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.init('https://jsonplaceholder.typicode.com', { hooks })
// 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
Example usecase for Upload File:
export async function postImportFile(formData: FormData) {
const [postErr, postData] = await hypfRequest.post(`/api/upload-file/import`, {
body: formData,
})
if (postErr) {
throw postErr
}
return postData
}
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)
}
Debugging the library is possible but limited. You can pass true
to debug
option:
const requestWithHooks = hypf.init('https://jsonplaceholder.typicode.com', { debug: true })
This is designed to be useful to track an issue. Submit a PR to debug more areas in the code!
Hyperfetch is highly inspired by Hono, Got, Ky and Axios
Hyperfetch is MIT-licensed and Open Source Software by fzn0x and contributors from Hono and the Hyperfetch community: