Axios

Most popular HTTP client library for JavaScript/TypeScript. Features promise-based API, request/response transformation, automatic JSON handling, interceptors, error handling, and timeout capabilities. Works in both browser and Node.js environments with extensive configuration options.

HTTP ClientJavaScriptTypeScriptNode.jsWeb APIPromise

Library

Axios

Overview

Axios is developed as a "Promise based HTTP client for the browser and node.js" and is an HTTP client library. With isomorphic design that works with the same codebase in both browser and Node.js environments, it uses the native Node.js HTTP module on the server-side and XMLHttpRequests on the client-side. It provides automatic JSON transformation, request/response interceptors, robust error handling, and supports older browsers including IE11.

Details

Axios 1.7.9 remains the most popular HTTP client library in the JavaScript ecosystem as of 2025, with active development. It provides complete TypeScript support with TypeScript 4.7+ and flexible module resolution with esModuleInterop. Automatic JSON transformation eliminates the need for manual parsing, and global interceptors enable unified preprocessing and postprocessing of requests and responses. XMLHttpRequest-based architecture ensures stable operation even on older browsers including IE11.

Key Features

  • Automatic JSON Transformation: Automatic conversion of JSON responses to JavaScript objects
  • Interceptors: Global preprocessing and postprocessing functionality for requests and responses
  • Default Configuration: Reduction of code duplication through predefined settings like base URLs and headers
  • Error Handling: Robust error handling with detailed error messages
  • Wide Browser Support: Stable operation on older browsers including IE11
  • TypeScript Integration: Built-in TypeScript definitions and error type guards

Pros and Cons

Pros

  • Most established HTTP client in JavaScript ecosystem (10+ years of development)
  • High compatibility through wide browser support including IE11
  • Improved development efficiency through automatic JSON conversion and rich configuration options
  • Unified request/response processing through interceptors
  • Robust error handling and ease of debugging
  • Rich ecosystem with plugins and extensions

Cons

  • Adds 35KB to bundle size (Fetch API adds 0KB)
  • Fetch API can achieve equivalent functionality in modern browsers
  • Overkill for lightweight API client needs
  • Some new features limited due to XMLHttpRequest base
  • Configuration complexity due to feature richness
  • Slightly higher learning curve compared to fetch API

References

Code Examples

Basic Setup

# Install Axios
npm install axios

# TypeScript type definitions (usually included automatically)
# npm install @types/axios  # Not needed with latest versions

Import and Basic Usage

// ES6 modules (recommended)
import axios from 'axios';

// CommonJS (Node.js) - with TypeScript type support
const axios = require('axios').default;

// Simple GET request
axios.get('/user?ID=12345')
  .then(function (response) {
    // handle success
    console.log(response.data);
    console.log(response.status);
    console.log(response.headers);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })
  .finally(function () {
    // always executed
  });

// Alternative method with separate parameters
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response.data);
  })
  .catch(function (error) {
    console.log(error);
  });

Modern Approach with Async/Await

// async/await usage
async function getUser() {
  try {
    const response = await axios.get('/user?ID=12345');
    console.log('User data:', response.data);
    console.log('Status:', response.status);
    return response.data;
  } catch (error) {
    console.error('Error occurred:', error);
    throw error;
  }
}

// POST request example
async function createUser(userData) {
  try {
    const response = await axios.post('/user', {
      firstName: 'John',
      lastName: 'Doe',
      email: '[email protected]'
    });
    console.log('User created successfully:', response.data);
    return response.data;
  } catch (error) {
    console.error('User creation error:', error);
    throw error;
  }
}

// Multiple concurrent requests
async function getUserWithPermissions(userId) {
  try {
    const [userResponse, permissionsResponse] = await Promise.all([
      axios.get(`/user/${userId}`),
      axios.get(`/user/${userId}/permissions`)
    ]);
    
    return {
      user: userResponse.data,
      permissions: permissionsResponse.data
    };
  } catch (error) {
    console.error('Data retrieval error:', error);
    throw error;
  }
}

Instance Creation and Custom Configuration

// Creating custom instance
const apiClient = axios.create({
  baseURL: 'https://api.example.com/v1',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': 'your-api-key'
  }
});

// Global default configuration
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = 'Bearer your-token';
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

// Configuration precedence test
const instance = axios.create();
instance.defaults.timeout = 2500; // Instance default

// Request-specific configuration (highest priority)
instance.get('/longRequest', {
  timeout: 5000
});

// Complete configuration options example
const config = {
  url: '/user',
  method: 'get',
  baseURL: 'https://api.example.com',
  headers: {'X-Requested-With': 'XMLHttpRequest'},
  params: { ID: 12345 },
  data: { firstName: 'Fred' },
  timeout: 1000,
  withCredentials: false,
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },
  responseType: 'json',
  validateStatus: function (status) {
    return status >= 200 && status < 300;
  }
};

axios(config)
  .then(function (response) {
    console.log(response);
  });

Common Processing with Interceptors

// Request interceptor
axios.interceptors.request.use(
  function (config) {
    // Processing before request is sent
    console.log('Sending request:', config);
    
    // Automatic addition of auth token
    const token = localStorage.getItem('authToken');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    
    // Record request time
    config.metadata = { startTime: new Date() };
    
    return config;
  },
  function (error) {
    // Processing for request error
    console.error('Request error:', error);
    return Promise.reject(error);
  }
);

// Response interceptor
axios.interceptors.response.use(
  function (response) {
    // Processing for 2xx status codes
    console.log('Response received:', response);
    
    // Calculate response time
    const endTime = new Date();
    const duration = endTime - response.config.metadata.startTime;
    console.log(`Request duration: ${duration}ms`);
    
    return response;
  },
  function (error) {
    // Processing for error status codes
    console.error('Response error:', error);
    
    if (error.response.status === 401) {
      // Redirect to login page for authentication errors
      localStorage.removeItem('authToken');
      window.location.href = '/login';
    }
    
    return Promise.reject(error);
  }
);

// Removing interceptors
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

Error Handling and Debugging

// Detailed error handling
axios.get('/user/12345')
  .catch(function (error) {
    if (error.response) {
      // Server responded with status code outside 2xx range
      console.log('Error data:', error.response.data);
      console.log('Status:', error.response.status);
      console.log('Headers:', error.response.headers);
      
      // Status code-specific processing
      switch (error.response.status) {
        case 400:
          console.error('Bad Request: Invalid request');
          break;
        case 401:
          console.error('Authentication Error: Login required');
          break;
        case 404:
          console.error('Resource not found');
          break;
        case 500:
          console.error('Server error occurred');
          break;
        default:
          console.error('Unexpected error occurred');
      }
    } else if (error.request) {
      // Request was sent but no response received
      console.log('Network error:', error.request);
      console.error('Cannot connect to server');
    } else {
      // Error occurred during request setup
      console.log('Configuration error:', error.message);
    }
    
    // Request configuration information
    console.log('Request config:', error.config);
    
    // Detailed error information (JSON format)
    console.log('Detailed error info:', error.toJSON());
  });

// Custom error validation
axios.get('/user/12345', {
  validateStatus: function (status) {
    return status < 500; // Only consider status codes below 500 as success
  }
});

// Timeout and retry functionality implementation
async function requestWithRetry(config, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await axios(config);
      return response;
    } catch (error) {
      console.log(`Attempt ${i + 1} failed:`, error.message);
      
      if (i === maxRetries - 1) {
        throw error; // Throw error if last attempt fails
      }
      
      // Wait with exponential backoff
      const delay = Math.pow(2, i) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

// Usage example
try {
  const response = await requestWithRetry({
    url: '/api/unstable-endpoint',
    timeout: 5000
  });
  console.log('Success:', response.data);
} catch (error) {
  console.error('Finally failed:', error);
}

Form Data and File Upload

// Using FormData
const formData = new FormData();
formData.append('username', 'johndoe');
formData.append('email', '[email protected]');
formData.append('avatar', fileInput.files[0]);

axios.post('/user/upload', formData, {
  headers: {
    'Content-Type': 'multipart/form-data'
  },
  onUploadProgress: function (progressEvent) {
    const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
    console.log(`Upload progress: ${percentCompleted}%`);
  }
})
.then(function (response) {
  console.log('Upload successful:', response.data);
});

// Sending URL-encoded data
const params = new URLSearchParams();
params.append('name', 'John Doe');
params.append('email', '[email protected]');

axios.post('/user', params, {
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  }
});

// Automatic FormData header setup interceptor
axios.interceptors.request.use(config => {
  if (config.data instanceof FormData) {
    Object.assign(config.headers, config.data.getHeaders());
  }
  return config;
});

// File download
async function downloadFile(url, filename) {
  try {
    const response = await axios({
      method: 'GET',
      url: url,
      responseType: 'blob',
      onDownloadProgress: function (progressEvent) {
        const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
        console.log(`Download progress: ${percentCompleted}%`);
      }
    });

    // Download file in browser
    const url_blob = window.URL.createObjectURL(new Blob([response.data]));
    const link = document.createElement('a');
    link.href = url_blob;
    link.setAttribute('download', filename);
    document.body.appendChild(link);
    link.click();
    link.remove();
    
    console.log('Download completed');
  } catch (error) {
    console.error('Download error:', error);
  }
}

Request Cancellation

// Cancellation using AbortController (recommended)
const controller = new AbortController();

axios.get('/user/12345', {
  signal: controller.signal
})
.then(function (response) {
  console.log(response.data);
})
.catch(function (error) {
  if (axios.isCancel(error)) {
    console.log('Request was cancelled:', error.message);
  } else {
    console.error('Error:', error);
  }
});

// Cancel request after 5 seconds
setTimeout(() => {
  controller.abort('Operation timed out');
}, 5000);

// Using deprecated CancelToken (for backward compatibility)
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
})
.catch(function (thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request cancelled:', thrown.message);
  } else {
    console.error('Error:', thrown);
  }
});

// Execute cancellation
source.cancel('Cancelled by user');

// Batch cancellation of multiple requests
const cancelTokenSource = axios.CancelToken.source();

Promise.all([
  axios.get('/user/12345', { cancelToken: cancelTokenSource.token }),
  axios.get('/user/12345/permissions', { cancelToken: cancelTokenSource.token })
])
.then(function (responses) {
  console.log('All results:', responses);
})
.catch(function (error) {
  if (axios.isCancel(error)) {
    console.log('All requests were cancelled');
  }
});

// Conditional cancellation
setTimeout(() => {
  cancelTokenSource.cancel('Operation was cancelled');
}, 3000);