Migration Guide
Migrate to CallApi from other fetch libraries
This guide helps you migrate from other popular fetch libraries to CallApi with step-by-step instructions and code examples.
From Axios
Installation
First, install CallApi alongside or instead of Axios:
pnpm install @zayne-labs/callapi # Optionally remove axios npm uninstall axiosBasic Request
import axios from "axios";
// GET request
const responseOne = await axios.get("https://api.example.com/users");
const users = responseOne.data;
// POST request
const responseTwo = await axios.post("https://api.example.com/users", {
name: "John Doe",
email: "john@example.com",
});
const user = responseTwo.data;import { callApi } from "@zayne-labs/callapi";
// GET request
const { data: users } = await callApi("https://api.example.com/users");
// POST request
const { data: user } = await callApi("@post/https://api.example.com/users", {
body: {
name: "John Doe",
email: "john@example.com",
},
});Creating an Instance
import axios from "axios";
const api = axios.create({
baseURL: "https://api.example.com",
timeout: 10000,
headers: {
"Content-Type": "application/json",
},
});
const response = await api.get("/users");import { createFetchClient } from "@zayne-labs/callapi";
const api = createFetchClient({
baseURL: "https://api.example.com",
timeout: 10000,
headers: {
"Content-Type": "application/json",
},
});
const { data } = await api("/users");Interceptors → Hooks
import axios from "axios";
const api = axios.create({
baseURL: "https://api.example.com",
});
// Request interceptor
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// Response interceptor
api.interceptors.response.use(
(response) => {
console.log("Response:", response.status);
return response;
},
(error) => {
if (error.response?.status === 401) {
// Redirect to login
}
return Promise.reject(error);
}
);import { createFetchClient } from "@zayne-labs/callapi";
const api = createFetchClient({
baseURL: "https://api.example.com",
// Request hook
onRequest: ({ request }) => {
const token = localStorage.getItem("token");
if (token) {
request.headers.set("Authorization", `Bearer ${token}`);
}
},
// Success hook
onSuccess: ({ response }) => {
console.log("Response:", response.status);
},
// Error hook
onError: ({ response }) => {
if (response?.status === 401) {
// Redirect to login
}
},
});Error Handling
import axios from "axios";
try {
const response = await axios.get("/users");
const users = response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
console.error("Status:", error.response?.status);
console.error("Data:", error.response?.data);
console.error("Message:", error.message);
} else {
console.error("Unexpected error:", error);
}
}import { callApi } from "@zayne-labs/callapi";
import { isHTTPError } from "@zayne-labs/callapi/utils";
const { data: users, error } = await callApi("/users");
if (error) {
if (isHTTPError(error)) {
console.error("Status:", error.response?.status);
console.error("Data:", error.errorData);
console.error("Message:", error.message);
} else {
console.error("Unexpected error:", error.message);
}
}Request Cancellation
import axios from "axios";
const controller = new AbortController();
try {
const response = await axios.get("/users", {
signal: controller.signal,
});
} catch (error) {
if (axios.isCancel(error)) {
console.log("Request cancelled");
}
}
// Cancel the request
controller.abort();import { callApi } from "@zayne-labs/callapi";
const controller = new AbortController();
const { data, error } = await callApi("/users", {
signal: controller.signal,
});
if (error?.name === "AbortError") {
console.log("Request cancelled");
}
// Cancel the request
controller.abort();TypeScript Support
import axios from "axios";
type User = {
email: string;
id: number;
name: string;
};
// Manual typing
const response = await axios.get<User>("/users/1");
const user = response.data; // Type: User
// No runtime validationimport { callApi } from "@zayne-labs/callapi";
import { z } from "zod";
const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string(),
});
// Automatic type inference + runtime validation
const { data: user } = await callApi("/users/1", {
schema: { data: userSchema },
});
// Type automatically inferred from schema!From Ky
Installation
bash npm install @zayne-labs/callapi npm uninstall ky bash pnpm add @zayne-labs/callapi pnpm remove ky bash yarn add @zayne-labs/callapi yarn remove ky bash bun add @zayne-labs/callapi bun remove ky Basic Usage
import ky from "ky";
// GET request
const users = await ky.get("https://api.example.com/users").json();
// POST request
const user = await ky
.post("https://api.example.com/users", {
json: {
name: "John Doe",
email: "john@example.com",
},
})
.json();import { callApi } from "@zayne-labs/callapi";
// GET request
const { data: users } = await callApi("https://api.example.com/users");
// POST request
const { data: user } = await callApi("@post/https://api.example.com/users", {
body: {
name: "John Doe",
email: "john@example.com",
},
});Creating an Instance
import ky from "ky";
const api = ky.create({
prefixUrl: "https://api.example.com",
timeout: 10000,
retry: 2,
});
const users = await api.get("users").json();import { createFetchClient } from "@zayne-labs/callapi";
const api = createFetchClient({
baseURL: "https://api.example.com",
timeout: 10000,
retryAttempts: 2,
});
const { data: users } = await api("/users");Hooks
import ky from "ky";
const api = ky.create({
hooks: {
beforeRequest: [
(request) => {
request.headers.set("Authorization", `Bearer ${token}`);
},
],
afterResponse: [
(request, options, response) => {
console.log("Response:", response.status);
},
],
},
});import { createFetchClient } from "@zayne-labs/callapi";
const api = createFetchClient({
onRequest: ({ request }) => {
request.headers.set("Authorization", `Bearer ${token}`);
},
onSuccess: ({ response }) => {
console.log("Response:", response.status);
},
});Error Handling
import ky from "ky";
try {
const users = await ky.get("api/users").json();
} catch (error) {
if (error instanceof ky.HTTPError) {
console.error("Status:", error.response.status);
const errorData = await error.response.json();
console.error("Error data:", errorData);
}
}import { callApi } from "@zayne-labs/callapi";
import { isHTTPError } from "@zayne-labs/callapi/utils";
const { data: users, error } = await callApi("api/users");
if (isHTTPError(error)) {
console.error("Status:", error.response?.status);
console.error("Error data:", error.errorData); // Already parsed!
}From Ofetch
Installation
bash npm install @zayne-labs/callapi npm uninstall ofetch bash pnpm add @zayne-labs/callapi pnpm remove ofetch bash yarn add @zayne-labs/callapi yarn remove ofetch bash bun add @zayne-labs/callapi bun remove ofetch Basic Usage
import { ofetch } from "ofetch";
// GET request
const users = await ofetch("https://api.example.com/users");
// POST request
const user = await ofetch("https://api.example.com/users", {
method: "POST",
body: {
name: "John Doe",
email: "john@example.com",
},
});import { callApi } from "@zayne-labs/callapi";
// GET request
const { data: users } = await callApi("https://api.example.com/users");
// POST request
const { data: user } = await callApi("@post/https://api.example.com/users", {
body: {
name: "John Doe",
email: "john@example.com",
},
});Creating an Instance
import { ofetch } from "ofetch";
const api = ofetch.create({
baseURL: "https://api.example.com",
retry: 2,
retryDelay: 1000,
});
const users = await api("/users");import { createFetchClient } from "@zayne-labs/callapi";
const api = createFetchClient({
baseURL: "https://api.example.com",
retryAttempts: 2,
retryDelay: 1000,
});
const { data: users } = await api("/users");Interceptors → Hooks
import { ofetch } from "ofetch";
const api = ofetch.create({
baseURL: "https://api.example.com",
onRequest: ({ options }) => {
options.headers = {
...options.headers,
Authorization: `Bearer ${token}`,
};
},
onResponse: ({ response }) => {
console.log("Response:", response.status);
},
onResponseError: ({ response }) => {
console.error("Error:", response.status);
},
});import { createFetchClient } from "@zayne-labs/callapi";
const api = createFetchClient({
baseURL: "https://api.example.com",
onRequest: ({ request }) => {
request.headers.set("Authorization", `Bearer ${token}`);
},
onSuccess: ({ response }) => {
console.log("Response:", response.status);
},
onError: ({ response }) => {
console.error("Error:", response?.status);
},
});Error Handling
import { ofetch } from "ofetch";
try {
const users = await ofetch("/users");
} catch (error) {
console.error("Error:", error.data);
console.error("Status:", error.statusCode);
}import { callApi } from "@zayne-labs/callapi";
import { isHTTPError } from "@zayne-labs/callapi/utils";
const { data: users, error } = await callApi("/users");
if (isHTTPError(error)) {
console.error("Error:", error.errorData);
console.error("Status:", error.response?.status);
}Common Patterns
Authentication
// Various approaches depending on library
// Usually involves interceptors or hooksimport { createFetchClient } from "@zayne-labs/callapi";
const api = createFetchClient({
baseURL: "https://api.example.com",
onRequest: ({ request, options }) => {
const token = localStorage.getItem("token");
if (token) {
options.auth = token;
}
},
onError: async ({ error, response, options }) => {
// Refresh token on 401
if (response?.status === 401) {
const newToken = await refreshToken();
localStorage.setItem("token", newToken);
// Retry request
options.retryAttempts = 1;
}
},
});File Upload with Progress
import axios from "axios";
const formData = new FormData();
formData.append("file", file);
const response = await axios.post("/upload", formData, {
onUploadProgress: (progressEvent) => {
const progress = (progressEvent.loaded / progressEvent.total) * 100;
console.log(`Upload progress: ${progress}%`);
},
});import { callApi } from "@zayne-labs/callapi";
const formData = new FormData();
formData.append("file", file);
const { data } = await callApi("@post/upload", {
body: formData,
onResponseStream: ({ event }) => {
if (event.type === "progress") {
console.log(`Upload progress: ${event.progress}%`);
}
},
});Query Parameters
// Manual URL construction
const responseOne = await api.get("/users?role=admin&status=active");
// Or using params option (varies by library)
const responseTwo = await api.get("/users", {
params: { role: "admin", status: "active" },
});import { callApi } from "@zayne-labs/callapi";
// Built-in query helper
const { data: users } = await callApi("/users", {
query: { role: "admin", status: "active" },
});
// Automatically constructs: /users?role=admin&status=activeURL Parameters
// Manual URL construction
const userId = 123;
const response = await api.get(`/users/${userId}`);import { callApi } from "@zayne-labs/callapi";
// Built-in param substitution
const { data: user } = await callApi("/users/:id", {
params: { id: 123 },
});
// Automatically constructs: /users/123Migration Checklist
- Install
@zayne-labs/callapi - Update imports from
axios/ky/ofetchtocallApi - Replace
axios.create()orky.create()withcreateFetchClient() - Update HTTP method calls (
api.get(),api.post()) to eithercallApi('@method/path')or use themethodoption. - Convert interceptors to hooks (
onRequest,onSuccess,onError) - Update error handling to check the
errorproperty in the returned result object and useisHTTPError(error) - For React Query, see the React Query Integration guide.
Last updated on