A lightweight and flexible fetch enhancement library that works with vanilla JavaScript, React, and Preact.
Check the Documentation in JSR
- π Universal Compatibility β Seamlessly runs in all JavaScript environments, including Node.js, Bun, Deno, and browsers.
- βοΈ Tailored for React & Preact β Enjoy dedicated hooks with full-feature integration for both frameworks.
- π§ Endlessly Customizable β Design custom fetch functions tailored to your unique requirements.
- π TypeScript Native β Built-in TypeScript support ensures a flawless developer experience.
- π Powerful Middleware System β Leverage built-in middleware or create your own for extended functionality.
- π¦ Web API Driven β Crafted with a focus on modern Web APIs for seamless integration.
@pretch/core
- Core functionality and middleware system@pretch/react
- React hooks integration@pretch/preact
- Preact hooks integration
import { buildFetch } from "@pretch/core";
import { applyMiddlewares, defaultHeaders } from "@pretch/core/middleware";
const customFetch = buildFetch(
applyMiddlewares(
defaultHeaders({
"Content-Type": "application/json; charset=UTF-8",
}),
),
);
// Use your enhanced fetch
const response = await customFetch("https://api.example.com/todos/1");
const data = await response.json();
Pretch provides a built-in enhancer to apply middlewares on each request
import { buildFetch } from "@pretch/core";
import { applyMiddlewares, validateStatus } from "@pretch/core/middleware";
const customFetch = buildFetch(
applyMiddlewares(
validateStatus({
validate: (status) => 200 <= status && status <= 399,
errorFactory: (status, request, response) =>
new Error(`Error. Status code: ${status}`),
shouldCancelBody: true,
}),
),
);
import { buildFetch } from "@pretch/core";
import { applyMiddlewares, retry } from "@pretch/core/middleware";
const customFetch = buildFetch(
applyMiddlewares(
retry({
maxRetries: 2,
delay: 1_500,
}),
),
);
import { buildFetch } from "@pretch/core";
import { applyMiddlewares, defaultHeaders } from "@pretch/core/middleware";
const customFetch = buildFetch(
applyMiddlewares(
defaultHeaders({
"Content-Type": "application/json; charset=UTF-8",
}, {
strategy: "set", // Optional, by default the headers appended
}),
),
);
import { buildFetch } from "@pretch/core";
import { applyMiddlewares, authorization } from "@pretch/core/middleware";
const customFetch = buildFetch(
applyMiddlewares(
authorization(
"123456789abcdef",
"bearer",
{
shouldApplyToken: (request: Request) =>
new URL(request.url).pathname.startsWith("/api/"),
},
),
),
);
import { buildFetch } from "@pretch/core";
import {
applyMiddlewares,
type ErrorLogData,
logging,
type RequestLogData,
type ResponseLogData,
} from "@pretch/core/middleware";
const customFetch = buildFetch(
applyMiddlewares(
logging({
onRequest: async ({ request }: RequestLogData) => {
console.log(`Starting request to ${request.url}`);
},
onResponse: async ({ response }: ResponseLogData) => {
console.log(`Received response with status ${response.status}`);
},
onCatch: async ({ error }: ErrorLogData) => {
console.error(`Request failed:`, error);
},
}),
),
);
import { buildFetch } from "@pretch/core";
import { applyMiddlewares, proxy } from "@pretch/core/middleware";
const customFetch = buildFetch(
applyMiddlewares(
proxy(
"/api", // Forward all requests starting with /api
"https://api.example.com",
{
pathRewrite: (path: string) => path.replace(/^\/api/, ""), // Remove /api prefix
},
),
),
);
The React and Preact integration delivers powerful hooks for both automatic and manual fetching, complete with built-in state management. Both packages share a unified API and identical features, with the only difference being the package source for importing the hooks.
Key Features of the Hooks:
- π Loading & Error State Management β Effortlessly track request states with built-in tools.
- π‘ Type-Safe Response Handling β Enjoy confidence in your data with robust TypeScript support.
- βοΈ Request Enhancement β Easily customize and optimize fetch requests to meet your needs.
- π Seamless @pretch/core Integration β Fully compatible with middlewares, enhancers, and other advanced features provided by the @pretch/core package.
useFetch
automatically fetches the data when the component mounts. You can
refetch the data when the refetch
function is called.
import { useFetch } from "@pretch/react";
function MyComponent() {
const { data, loading, error, refetch } = useFetch(
"https://api.example.com/todos/1",
);
const handleClick = () => {
refetch();
};
return (
<div>
{loading ? "Loading..." : "Data: " + JSON.stringify(data)}
{error && <p>Error: {error.message}</p>}
<button onClick={handleClick} disabled={loading}>Refresh</button>
</div>
);
}
useLazyFetch
fetches the data manually. You can trigger the fetch with the
fetchData
function.
import { useLazyFetch } from "@pretch/react";
function MyComponent() {
const { data, loading, error, fetchData } = useLazyFetch({
url: "https://api.example.com/todos/1",
});
const handleClick = () => {
fetchData({
newOptions: {
method: "POST",
body: JSON.stringify({ title: "New Todo" }),
},
});
};
return (
<div>
{loading ? "Loading..." : "Data: " + JSON.stringify(data)}
{error && <p>Error: {error.message}</p>}
<button onClick={handleClick}>Create Todo</button>
</div>
);
}
The hook supports request enhancement through enhancer functions for customizing request behavior:
Custom enhancer: Implement your own enhancer function to modify the request behavior before it is sent.
import type { Enhancer, Handler } from "@pretch/core";
function authHeaderEnhancer(handler: Handler) {
return async (request: Request) => {
const modifiedRequest = new Request(request, {
headers: {
...request.headers,
"Authorization": "Bearer my-token",
},
});
return handler(modifiedRequest);
};
}
function MyComponent() {
const { data } = useFetch("https://example.com", {
enhancer: authHeaderEnhancer,
});
return (
<div>
Data: {JSON.stringify(data)}
</div>
);
}
Built-in middlewares: Otherwise, Pretch provides a built-in enhancer to apply middlewares on each request, including built-in middlewares.
import {
applyMiddlewares,
authorization,
defaultHeaders,
retry,
} from "@pretch/core";
import { useFetch, useLazyFetch } from "@precth/react";
function TodoList() {
const { data, loading, error, refetch } = useFetch(
"https://api.example.com/todos/",
{
enhancer: applyMiddlewares(
retry({
maxRetries: 2,
delay: 500,
}),
authorization("your-token", "bearer"),
),
},
);
const handleClick = () => { refetch() };
return (
<div>
{loading ? <span>Loading...</span> : (
<ul>
{data.map((todo) => {
<li>{todo.title}</li>;
})}
</ul>
)}
{error && <p>Error: {error.message}</p>}
<button onClick={handleClick}>Refresh</button>
</div>
);
}
function CreateTodo() {
const {data, fetchData, error, loading} = useLazyFetch({
url: "https://api.example.com/todos/",
enhancer: applyMiddlewares(
defaultHeaders({
"Content-Type": "application/json; charset=UTF-8",
}),
),
});
const handleSubmit = async (event: SubmitEvent ) => {
event.preventDefault();
const formData = new FormData(event.target as HTMLFormElement);
fetchData({
newOptions: {
method: "POST",
body: JSON.stringify(Object.fromEntries(formData.entries()))
}
})
};
return (
<form onSubmit={handleSubmit}>
<input name="title" >
<button>Create</button>
</form>
);
}
Struggling to find a simple yet customizable fetching hook library for Preact, I created @pretch/preact, focusing on ease of use, minimal abstraction, and alignment with Web APIs. This evolved into @pretch/core, a versatile package for fetch customization with built-in middlewares and enhancers, later extended to @pretch/react and @pretch/preact for React and Preact integration.
Contributions are welcome! Please feel free to submit a Pull Request.
Created by EGAMAGZ
MIT License
- Create useQuery hook inspired on @tanstack/react-query and redux query
- Develop and automatize tests for @pretch/preact and @pretch/react