Axios Interceptors: The Ultimate Guide to Mastering API Workflows

Axios interceptors Complete guide
Spread the love

Introduction: The Power of Axios Interceptors

Axios interceptors are a cornerstone of efficient API management in modern web development. They act as middleware, allowing developers to intercept, modify, and track HTTP requests and responses before they reach your application logic. Whether you’re building a small React app or a large-scale enterprise system, interceptors help you:

  • Centralize repetitive tasks (e.g., adding authentication headers).
  • Handle errors globally (e.g., redirecting users after a 401 error).
  • Transform data (e.g., parsing responses or logging metrics).

This guide dives deep into interceptors, covering everything from basic setup to advanced patterns like token refresh and retry logic. By the end, you’ll have the tools to streamline your API workflows and solve common pain points.

What Are Axios Interceptors?

Interceptors are functions that run automatically during the lifecycle of an HTTP request:

  • Request Interceptors : Execute before a request is sent to the server.
  • Response Interceptors : Execute after a response is received.

They’re particularly useful for decoupling logic from your API calls, ensuring cleaner code and easier maintenance.

Key Features For Axios Interceptors

  1. Global Control : Apply changes to all requests/responses.
  2. Error Handling : Catch and manage errors in one place.
  3. Data Transformation : Modify payloads or responses on the fly.
  4. Performance Tracking : Measure API latency and log metrics.

Core Concepts & Execution Flow

Request Interceptors

These run before the request is sent. Common use cases:

  • Adding headers (e.g., Authorization, Content-Type).
  • Modifying request data (e.g., stringifying JSON).
  • Logging request details for debugging.

Example Of Request Interceptors :

axios.interceptors.request.use(  
  (config) => {  
    // Add auth token from localStorage  
    const token = localStorage.getItem('auth_token');  
    if (token) config.headers.Authorization = `Bearer ${token}`;  
    return config;  
  },  
  (error) => {  
    // Handle request errors (e.g., network issues)  
    console.error('Request failed:', error);  
    return Promise.reject(error);  
  }  
);  

Response Interceptors

These run after the response is received. Common use cases:

  • Handling non-2xx status codes (e.g., 401, 500).
  • Parsing response data (e.g., extracting response.data).
  • Logging response times or errors.

Example Of Response Interceptors :

axios.interceptors.response.use(  
  (response) => {  
    // Simplify response by returning only data  
    return response.data;  
  },  
  (error) => {  
    if (error.response?.status === 401) {  
      // Redirect to login for unauthorized access  
      window.location.href = '/login';  
    }  
    return Promise.reject(error);  
  }  
);  

Advanced Use Cases Of Interceptors

Token Refresh with Retry Logic

When a token expires, interceptors can automatically refresh it and retry the failed request:

// Create an axios instance  
const api = axios.create({ baseURL: '/api' });  

// Track ongoing refresh requests  
let isRefreshing = false;  
let failedQueue = [];  

// Response interceptor for token refresh  
api.interceptors.response.use(  
  (response) => response,  
  async (error) => {  
    const originalRequest = error.config;  
    if (error.response?.status === 401 && !originalRequest._retry) {  
      if (isRefreshing) {  
        // Queue the request until the token is refreshed  
        return new Promise((resolve, reject) => {  
          failedQueue.push({ resolve, reject });  
        })  
        .then(() => api(originalRequest))  
        .catch((err) => Promise.reject(err));  
      }  
      originalRequest._retry = true;  
      isRefreshing = true;  
      try {  
        // Call your auth API to refresh the token  
        const { token } = await refreshToken();  
        localStorage.setItem('auth_token', token);  
        // Retry all queued requests  
        failedQueue.forEach((p) => p.resolve());  
        return api(originalRequest);  
      } catch (err) {  
        failedQueue.forEach((p) => p.reject(err));  
        localStorage.removeItem('auth_token');  
        window.location.href = '/login';  
        return Promise.reject(err);  
      } finally {  
        isRefreshing = false;  
        failedQueue = [];  
      }  
    }  
    return Promise.reject(error);  
  }  
);  

Global Error Handling

Centralize error logging and user feedback:

axios.interceptors.response.use(  
  (response) => response,  
  (error) => {  
    // Log errors to a monitoring service like Sentry  
    Sentry.captureException(error);  
    // Show user-friendly messages  
    if (error.response?.status >= 500) {  
      toast.error('Something went wrong. Please try again later.');  
    }  
    return Promise.reject(error);  
  }  
);  

Performance Tracking

Measure API latency to optimize performance:

axios.interceptors.request.use((config) => {  
  config.metadata = { startTime: new Date() };  
  return config;  
});  

axios.interceptors.response.use(  
  (response) => {  
    const endTime = new Date();  
    const duration = endTime - response.config.metadata.startTime;  
    console.log(`API call to ${response.config.url} took ${duration}ms`);  
    return response;  
  },  
  (error) => {  
    // Track failed requests  
    console.error(`API call failed after ${duration}ms`);  
    return Promise.reject(error);  
  }  
);  

Best Practices

  • Organize Interceptors Separately: Create a dedicated axiosConfig.js file to keep your codebase clean.
  • Avoid Silent Failures: Always propagate errors with Promise.reject(error) to prevent unhandled rejections.
  • Test Edge Cases: Simulate scenarios like Expired tokens, Network outages, Server timeouts. For More information read our blog about how to handle Axios Common Errors.
  • TypeScript Integration: Define types for interceptors to avoid runtime errors.

Troubleshooting Common Issues

  • Interceptors Stop Working After Updates: Newer Axios versions may require interceptors to be added to the instance , not the global axios object.
  • Memory Leaks: Avoid adding interceptors inside components. Instead, register them once during app initialization.
  • Conflicting Interceptors: Use axios.interceptors.request.eject() to remove outdated interceptors.

Real-World Examples

Logging Interceptor

Track all API interactions for debugging:

axios.interceptors.request.use((config) => {  
  console.log('Request:', config.method.toUpperCase(), config.url);  
  return config;  
});  

axios.interceptors.response.use(  
  (response) => {  
    console.log('Response:', response.status, response.config.url);  
    return response;  
  },  
  (error) => {  
    console.error('Error:', error.message, error.config.url);  
    return Promise.reject(error);  
  }  
);  

Dynamic Base URL

Switch environments (dev/staging/production) dynamically:

axios.interceptors.request.use((config) => {  
  config.baseURL = process.env.NODE_ENV === 'production'  
    ? 'https://api.production.com'  
    : 'https://api.dev.com';  
  return config;  
});  

Conclusion: Elevate Your API Workflow

Axios interceptors are a Swiss Army knife for API management. By mastering them, you’ll write cleaner code, reduce redundancy, and handle edge cases with ease. Whether you’re debugging errors, optimizing performance, or securing requests, interceptors provide a centralized solution.

FAQs

How do I handle 401 Unauthorized errors globally with interceptors?

Use a response interceptor to check for 401 status codes. When detected, redirect users to a login page or trigger a token refresh flow. Ensure you propagate the error using Promise.reject() to avoid silent failures.

Can interceptors automatically retry failed requests (e.g., expired tokens)?

Yes. Implement a retry mechanism in the response interceptor. Track failed requests, refresh the token (if applicable), and retry the original request. Use a queue to manage concurrent retries and avoid race conditions.

Can interceptors track API performance or latency?

Yes. Use a request interceptor to record start times and a response interceptor to calculate duration. Log metrics to monitor performance bottlenecks.

Can interceptors modify headers for all requests?

Yes. Use a request interceptor to add headers (e.g., authentication tokens) to every outgoing request. Fetch tokens from secure storage (e.g., localStorage) dynamically.


Spread the love

Similar Posts