npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

npm version license

✔ 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-query

Peer 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 api also 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 401 response 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