Axios Integration

Difficulty: Advanced

Axios is an HTTP client library that improves on the native fetch API with features like automatic JSON parsing, request/response interceptors, timeout support, and better error handling. While fetch is built into browsers, Axios provides a more ergonomic API and is especially useful in production applications that need consistent error handling and authentication headers.

The recommended pattern is to create an Axios instance with a base URL and default configuration, then export it for use throughout the app. This centralises your API configuration in one place. If your API base URL or default headers change, you update one file instead of every fetch call.

Interceptors are the most powerful feature of Axios. A request interceptor runs before every request - the most common use is attaching the Authorization header with a JWT token. A response interceptor runs after every response - you can use it to handle 401 errors globally (redirect to login), transform response data, or log errors. This eliminates repetitive error handling in every component.

Error handling in Axios is more structured than fetch. Fetch only rejects on network errors, not on HTTP error codes (404, 500 still resolve). Axios rejects on any non-2xx status code, making it easier to catch errors in .catch() or try/catch. The error object includes response (server responded with error), request (no response received), and message (setup error).

A typical production setup creates an Axios instance, adds a request interceptor for auth tokens, adds a response interceptor for global error handling (401 redirect, toast notifications), and exports the instance. Components and React Query queryFn functions import this instance and use it for all API calls.

Code examples

Creating a configured Axios instance

import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.example.com/v1',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Usage
const getUser = (id) => api.get(`/users/${id}`);
const createUser = (data) => api.post('/users', data);
const updateUser = (id, data) => api.put(`/users/${id}`, data);
const deleteUser = (id) => api.delete(`/users/${id}`);

export default api;

axios.create returns a new instance with the given defaults. All requests made through this instance inherit the baseURL, timeout, and headers.

Request and response interceptors

import api from './api';

// Request interceptor: attach auth token
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: handle global errors
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    if (error.response?.status === 500) {
      console.error('Server error - please try again later');
    }
    return Promise.reject(error);
  }
);

The request interceptor reads the token from storage and injects it into every request. The response interceptor handles 401 (redirect to login) and 500 (log error) globally, so individual components don't need to.

Axios error handling structure

async function fetchData() {
  try {
    const response = await api.get('/data');
    return response.data;
  } catch (error) {
    if (error.response) {
      // Server responded with non-2xx status
      console.log('Status:', error.response.status);
      console.log('Data:', error.response.data);
    } else if (error.request) {
      // Request was made but no response received
      console.log('No response received');
    } else {
      // Error setting up the request
      console.log('Setup error:', error.message);
    }
    throw error;
  }
}

Axios errors have three categories: response errors (server replied with error code), request errors (network failure), and setup errors (bad config). This structure lets you handle each case appropriately.

Key points

Concepts covered

axios instance, interceptors, request config, error handling, base URL, headers