Core fetch utility for Onyx Framework
npm install @kawaiininja/fetchSecureStoragePlugin (with localStorage fallback) for secure token management.
HttpOnly cookies + Automatic CSRF token rotation.
ApiProvider. This sets the design system and security policy for every request.
jsx
// src/main.jsx or App.jsx
import { ApiProvider } from "@kawaiininja/fetch";
const apiConfig = {
baseUrl: "https://api.myapp.com", // Base URL for all requests
version: "v1", // Automatically appends /v1 to non-absolute paths
debug: true, // Detailed console logs for security & network
timeout: 5000, // Global fallback timeout (default 5s)
retries: 3, // Global retry attempt count
disableCsrf: false, // Set true for local development or non-CSRF backends
onError: (msg, status) => {
showToast(${status || "Error"}: ${msg});
},
};
ReactDOM.createRoot(document.getElementById("root")).render(
,
);
`
---
📖 Essential Usage
$3
useFetch is designed to be the primary way you interact with your API. It handles state, mounting logic, and method injection.
`jsx
import { useFetch } from "@kawaiininja/fetch";
export const UserList = () => {
// 1. Initial configuration
// Note: state contains { data, loading, error, status }
const { state, isLoading, isSuccess, get } = useFetch("/users", {
swr: true,
revalidateOnFocus: true,
});
// Access data via state.data
const users = state.data;
if (isLoading && !users) return ;
return (
{users?.map((u) => (
- {u.name}
))}
);
};
`
$3
Don't use fetch() or axios for buttons. Use the injected methods to keep security tokens consistent.
`jsx
const CommentBox = ({ postId }) => {
const { post, isLoading } = useFetch("/comments");
const save = async (text) => {
// Methods return the final parsed data or undefined if failed
const result = await post({ text, postId });
if (result) alert("Saved!");
};
return (
);
};
`
---
🏗️ Advanced Guides
$3
While ApiProvider has a global onError, you can handle errors locally within a request to provide specific feedback (like inline form validation).
`javascript
const { post, state } = useFetch("/update-profile");
const handleSave = async () => {
try {
await post(formData);
} catch (err) {
// err.message will contain the server error or network issue
console.log("Local error handling:", err.message);
}
};
`
$3
Sometimes you want to update the UI instantly (Optimistic UI) before the server responds.
`javascript
const { updateData, post } = useFetch("/settings");
const toggleOption = async (id) => {
// 1. Update UI instantly
updateData({ [id]: true });
// 2. Sync with server in background
await post({ id, value: true });
};
`
$3
The hook automatically refetches if the endpoint or dedupeKey changes, making it perfect for search or filtered lists.
`javascript
const { state } = useFetch(/products?category=${selectedCategory});
// This will automatically fire whenever selectedCategory updates!
`
---
⚙️ Configuration API Reference
$3
| Property | Type | Default | Description |
| :------------ | :--------- | :----------- | :---------------------------------------------------- |
| baseUrl | string | Required | The root URL for all requests. |
| version | string | "v1" | Appended to paths that don't start with /. |
| timeout | number | 5000 | Global timeout in MS. |
| retries | number | 3 | Attempts before giving up. |
| disableCsrf | boolean | false | Skips CSRF token retrieval if true. |
| debug | boolean | false | Enables verbose security and network logs. |
| onError | function | - | Call: (msg: string, status: number \| null) => void |
$3
| Option | Type | Default | Description |
| :------------------ | :-------- | :--------- | :------------------------------------- |
| enabled | boolean | true | Set false to skip initial mount fetch. |
| swr | boolean | false | Enable caching + background updates. |
| revalidateOnFocus | boolean | false | Refetch when window is focused. |
| refreshInterval | number | 0 | Polling interval in MS. |
| staleTime | number | 300000 | Cache fresh for 5 minutes. |
| dedupeKey | string | endpoint | Custom key for caching logic. |
| timeout | number | (Global) | Per-hook timeout override. |
| retries | number | (Global) | Per-hook retry override. |
$3
| Property | Type | Description |
| :-------------------- | :-------------- | :------------------------------------------------------- |
| state | FetchState | Raw reactive state: { data, loading, error, status }. |
| isLoading | boolean | [Alias] for state.loading. |
| isError | boolean | [Alias] - true if state.error is present. |
| isSuccess | boolean | [Alias] - true if request is successful with data. |
| get(options) | function | Performs a GET request. |
| post(data, options) | function | Performs a POST request. |
| put/patch/delete | function | Corresponding HTTP methods. |
| upload(formData) | function | Multipart upload helper. |
| setData(data) | function | Manually override the local state.data. |
| updateData(partial) | function | Merge partial updates into state.data. |
---
🛡️ Security & Architecture
1. Context Initialization: ApiProvider creates an immutable configuration bridge.
2. Platform Awareness: The library automatically switches between Authorization headers (Native) and X-CSRF-Token (Web).
3. Execution Pipeline:
- Step 1: Check Cache (if SWR).
- Step 2: Ensure CSRF (if Web and not disabled).
- Step 3: Inject Auth Headers (Native Session Memory).
- Step 4: Execute fetch()` with recursive retry logic.