react-api-kit
v1.0.10
Published
Reusable Axios + TanStack Query API hooks for React
Downloads
626
Readme
🚀 react-api-kit
A lightweight, production-ready API client built on Axios + TanStack Query for React applications.
✔ Auto Bearer / Token / Custom auth headers
✔ Custom static headers per project
✔ Global error handling with toast support
✔ Auto logout on 401
✔ React Query–ready hooks (GET, POST, PUT, PATCH, DELETE)
✔ No UI dependencies — works with any toast library
📦 Installation
npm install react-api-kit axios @tanstack/react-queryPeer Dependencies: React ≥ 17, Axios ≥ 1, TanStack Query ≥ 4
⚡ Quick Start
1. Wrap your app with React Query Provider
// main.tsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<YourApp />
</QueryClientProvider>
);
}2. Configure the API (once at app startup)
// api.config.ts
import { setupApi } from "react-api-kit";
setupApi({
baseURL: "https://api.example.com",
tokenType: "Bearer",
getToken: () => localStorage.getItem("token"),
});Then import api.config.ts in your main.tsx before anything else.
🔧 setupApi — Full Configuration
setupApi({
// ─── Required ───────────────────────────────
baseURL: "https://api.example.com",
// ─── Auth Token ─────────────────────────────
tokenType: "Bearer", // "Bearer" | "Token" | "JWT" | "ApiKey" | any string
getToken: () => localStorage.getItem("token"), // return null to skip Authorization header
// ─── Custom Static Headers ──────────────────
headers: {
"X-Api-Key": "your-api-key", // sent with every request
"Accept-Language": "en",
"X-App-Version": "1.0.0",
},
// ─── Toast Notifications ────────────────────
toast: {
success: (msg) => toast.success(msg),
error: (msg) => toast.error(msg),
info: (msg) => toast.info(msg), // optional
warn: (msg) => toast.warn(msg), // optional
},
toastOptions: {
autoClose: 3000,
position: "top-right",
theme: "light", // "light" | "dark" | "colored"
},
// ─── Custom Error Messages ───────────────────
errorMessages: {
401: "Session expired. Please login again.",
403: "Access denied.",
404: "Not found.",
500: "Server error. Try again later.",
},
// ─── Global Callbacks ───────────────────────
onSuccess: (data) => console.log("Success:", data),
onError: (error, message) => console.error("Error:", message),
onLogout: () => {
localStorage.clear();
window.location.href = "/login"; // auto-called on 401
},
});🔑 Auth Header — tokenType Examples
| tokenType | getToken() returns | Header sent |
|-------------|----------------------|-------------|
| "Bearer" (default) | "abc123" | Authorization: Bearer abc123 |
| "Token" | "abc123" | Authorization: Token abc123 |
| "JWT" | "abc123" | Authorization: JWT abc123 |
| "ApiKey" | "abc123" | Authorization: ApiKey abc123 |
| "" (empty) | "abc123" | Authorization: abc123 |
| (not set) | "abc123" | Authorization: Bearer abc123 |
| "Bearer" | null / not set | (no Authorization header) |
📋 Custom Headers — headers Examples
Use headers for static values that never change (API keys, app identifiers, language, etc.):
// Single custom header
setupApi({
baseURL: "https://api.example.com",
headers: { "token_abc": "askfjshdfjk" },
});
// → Every request: token_abc: askfjshdfjk
// Multiple custom headers
setupApi({
baseURL: "https://api.example.com",
headers: {
"X-Api-Key": "your-api-key",
"X-App-ID": "my-app-001",
"Accept-Language": "en",
},
});
// Custom header + Bearer token together
setupApi({
baseURL: "https://api.example.com",
tokenType: "Bearer",
getToken: () => localStorage.getItem("token"),
headers: {
"X-Api-Key": "your-api-key", // static
},
});
// Both headers sent on every request🪝 Hooks
useApiQuery — Fetch data (GET)
const { data, isLoading, isError, refetch } = useApiQuery(
queryKey, // unique cache key array
method, // "GET" only for queries
endpoint, // API path
params?, // query string params (optional)
options? // TanStack Query options (optional)
);Examples:
// Basic GET
const { data, isLoading } = useApiQuery(["users"], "GET", "/users");
// GET with query params → /users?page=1&limit=10
const { data } = useApiQuery(["users", 1], "GET", "/users", { page: 1, limit: 10 });
// GET with TanStack options
const { data } = useApiQuery(["user", id], "GET", `/users/${id}`, undefined, {
enabled: !!id, // only fetch when id exists
staleTime: 1000 * 60, // cache for 1 minute
retry: 2, // retry twice on failure
});
// Usage in component
function UserList() {
const { data, isLoading, isError } = useApiQuery(["users"], "GET", "/users");
if (isLoading) return <p>Loading...</p>;
if (isError) return <p>Error!</p>;
return <ul>{data?.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}useApiMutation — Create / Update / Delete
const { mutate, mutateAsync, isPending, isError } = useApiMutation(
mutationKey, // unique key array
method, // "POST" | "PUT" | "PATCH" | "DELETE" | "GET"
invalidateKey? // query keys to refetch after success (optional)
);Call mutate with { endpoint, data }:
mutate({ endpoint: "/endpoint", data: { ...payload } });Examples:
POST — Create
const { mutate, isPending } = useApiMutation(
["createUser"],
"POST",
["users"] // refetches ["users"] query on success
);
const handleCreate = () => {
mutate({
endpoint: "/users",
data: { name: "John", email: "[email protected]" },
});
};PUT — Full Replace
const { mutate } = useApiMutation(["replaceUser"], "PUT", ["users"]);
mutate({
endpoint: `/users/${id}`,
data: { name: "John", email: "[email protected]", role: "admin" },
});PATCH — Partial Update
const { mutate } = useApiMutation(["updateUser"], "PATCH", ["users"]);
mutate({
endpoint: `/users/${id}`,
data: { name: "Updated Name" },
});DELETE — Remove
const { mutate } = useApiMutation(["deleteUser"], "DELETE", ["users"]);
mutate({ endpoint: `/users/${id}` });With callbacks
const { mutate } = useApiMutation(["createUser"], "POST", ["users"]);
mutate(
{ endpoint: "/users", data: { name: "John" } },
{
onSuccess: (data) => toast.success("User created!"),
onError: (err) => toast.error("Failed to create user"),
}
);Using mutateAsync (await)
const { mutateAsync, isPending } = useApiMutation(["createUser"], "POST");
const handleSubmit = async (formData) => {
try {
const result = await mutateAsync({ endpoint: "/users", data: formData });
console.log("Created:", result);
} catch (err) {
console.error(err);
}
};api — Direct Axios Instance
For cases where you need full control:
import { api } from "react-api-kit";
// GET
const users = await api.get("/users").then(res => res.data);
// GET with params
const res = await api.get("/orders", { params: { status: "pending" } });
// POST
const res = await api.post("/users", { name: "John" });
// PUT
const res = await api.put(`/users/${id}`, { name: "John", email: "[email protected]" });
// PATCH
const res = await api.patch(`/users/${id}`, { name: "Updated" });
// DELETE
const res = await api.delete(`/users/${id}`);
// Custom header for a single request only
const res = await api.get("/report", {
headers: { "X-Export-Format": "pdf" },
});All requests made via
apialso get the global auth header and custom headers automatically.
⚠️ Error Handling
Errors are handled automatically via the response interceptor with a 4-level priority:
| Priority | Source |
|----------|--------|
| 1️⃣ | error.response.data.message from backend |
| 2️⃣ | Your custom errorMessages[status] in setupApi |
| 3️⃣ | Built-in default messages (see table below) |
| 4️⃣ | Fallback: error.message or "Network Error" |
Built-in default status messages:
| Status | Default Message |
|--------|----------------|
| 400 | Bad request. Please check your input. |
| 401 | Session expired. Please login again. (+ auto logout) |
| 403 | You do not have permission to perform this action. |
| 404 | Requested resource not found. |
| 409 | Conflict occurred. Please try again. |
| 422 | Validation error. Please check the form. |
| 500 | Server error. Please try again later. |
401 Auto Logout: When a
401response is received,onLogout()is called automatically.
📁 Package Structure
src/
├── config.ts → ApiConfig interface + setupApi()
├── index.ts → Public exports
├── api/
│ ├── axios.ts → Axios instance + request interceptor (auth + headers)
│ ├── interceptors.ts → Response interceptor (error handling + auto logout)
│ └── globalApi.ts → GET / POST / PUT / PATCH / DELETE wrappers
└── hooks/
├── useApiQuery.ts → useQuery wrapper
└── useApiMutation.ts → useMutation wrapper🔗 Exports
import {
setupApi, // configure baseURL, token, headers, toast, etc.
api, // raw Axios instance (with interceptors)
useApiQuery, // TanStack Query hook for GET
useApiMutation, // TanStack Query hook for POST / PATCH / DELETE
} from "react-api-kit";📄 License
ISC © Ajay Kammar
