One SDK for every API. The type-safe API layer for TypeScript apps — REST, GraphQL, WebSockets, SSE, Firebase, and more.
HyperFetch Core is the foundation of the HyperFetch ecosystem. Every API call is a typed, immutable request object with built-in caching, queuing, retries, and offline support. It works in any JavaScript environment — browser, server, or edge — and connects to any API through pluggable adapters.
any againnpm install @hyper-fetch/core
import { createClient } from "@hyper-fetch/core";
// Single entry point — all requests inherit this base URL
const client = createClient({ url: "https://api.example.com" });
// Define a request with typed response — :userId becomes a required param
const getUser = client.createRequest<{ response: { id: number; name: string } }>()({
endpoint: "/users/:userId",
method: "GET",
});
// setParams is typed from the endpoint string, send() returns typed data
const { data, error } = await getUser.setParams({ userId: 1 }).send();
interface User {
id: number;
name: string;
email: string;
}
// GET request — only response type needed, params inferred from :userId
const getUser = client.createRequest<{ response: User }>()({
endpoint: "/users/:userId",
method: "GET",
});
// POST request — define both response and payload types
const createUser = client.createRequest<{
response: User;
payload: { name: string; email: string };
}>()({
endpoint: "/users",
method: "POST",
});
// Params are type-checked: { userId: number } required here
const { data } = await getUser.setParams({ userId: 1 }).send();
// Payload is type-checked: { name, email } required here
const { data: newUser } = await createUser.send({
data: { name: "Jane", email: "jane@example.com" },
});
// Define allowed query params — all are optional and type-checked
const listUsers = client.createRequest<{
response: User[];
queryParams: { page?: number; limit?: number; search?: string };
}>()({
endpoint: "/users",
method: "GET",
});
// Query params are appended to the URL: /users?page=1&limit=20&search=john
const { data } = await listUsers.setQueryParams({ page: 1, limit: 20, search: "john" }).send();
// Hook into the request lifecycle — track progress, log events, handle responses
const { data } = await getUser.setParams({ userId: 1 }).send({
onStart: ({ requestId }) => console.log(`Request ${requestId} started`),
onResponse: ({ response }) => console.log("Got data:", response.data),
onUploadProgress: ({ progress }) => console.log(`Upload: ${progress}%`),
onDownloadProgress: ({ progress }) => console.log(`Download: ${progress}%`),
});
// Transform the response before it reaches your code
const getUser = client
.createRequest<{ response: User }>()({
endpoint: "/users/:userId",
method: "GET",
})
.setResponseMapper((response) => ({
...response,
data: { ...response.data, name: response.data.name.toUpperCase() },
}));