Skip to main content
This guide helps you migrate from other popular fetch libraries to CallApi. Each section provides step-by-step instructions and code examples.

From Axios

Installation

First, install CallApi alongside or instead of Axios:
npm install @zayne-labs/callapi
# Optionally remove axios
npm uninstall axios

Basic Request

import axios from 'axios';

// GET request
const response = await axios.get('https://api.example.com/users');
const users = response.data;

// POST request
const response = await axios.post('https://api.example.com/users', {
  name: 'John Doe',
  email: '[email protected]',
});
const user = response.data;

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');

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
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

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);
  }
}

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();

TypeScript Support

import axios from 'axios';

type User = {
  id: number;
  name: string;
  email: string;
};

// Manual typing
const response = await axios.get<User>('/users/1');
const user = response.data; // Type: User

// No runtime validation

From Ky

Installation

npm install @zayne-labs/callapi
npm uninstall 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: '[email protected]',
  },
}).json();

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();

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);
      },
    ],
  },
});

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);
  }
}

From Ofetch

Installation

npm install @zayne-labs/callapi
npm uninstall 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: '[email protected]',
  },
});

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');

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);
  },
});

Error Handling

import { ofetch } from 'ofetch';

try {
  const users = await ofetch('/users');
} catch (error) {
  console.error('Error:', error.data);
  console.error('Status:', error.statusCode);
}

Common Patterns

Authentication

// Various approaches depending on library
// Usually involves interceptors or hooks

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}%`);
  },
});

Query Parameters

// Manual URL construction
const response = await api.get('/users?role=admin&status=active');

// Or using params option (varies by library)
const response = await api.get('/users', {
  params: { role: 'admin', status: 'active' },
});

URL Parameters

// Manual URL construction
const userId = 123;
const response = await api.get(`/users/${userId}`);

Migration Checklist

Step 1: Install CallApi

  • Install @zayne-labs/callapi
  • Optionally install validation library (Zod, Valibot, etc.)

Step 2: Update Imports

  • Replace old library imports with CallApi imports
  • Update import paths throughout your codebase

Step 3: Update API Client

  • Convert instance creation to createFetchClient
  • Map configuration options
  • Convert interceptors to hooks

Step 4: Update API Calls

  • Update request syntax
  • Add destructuring for data and error
  • Update error handling
  • Add schema validation (optional but recommended)

Step 5: Test

  • Test all API calls
  • Test error scenarios
  • Test authentication flows
  • Test file uploads
  • Test request cancellation

Step 6: Optimize

  • Add schema validation for type safety
  • Configure request deduplication
  • Set up retry strategies
  • Create custom plugins if needed
  • Add progress tracking for uploads/downloads

Need Help?

If you encounter issues during migration:
  1. Check the FAQ for common questions
  2. Review the API documentation
  3. Compare with library comparisons
  4. Open an issue on GitHub
Migration is usually straightforward and provides immediate benefits in bundle size, type safety, and developer experience.

Build docs developers (and LLMs) love