Intercept requests and responses to transform data, add authentication, handle errors, implement retry logic, or add logging before they are handled by then or catch.
Intercept requests before they are sent to the server. Useful for adding authentication tokens, logging, or modifying request data.
/**
* Add a request interceptor
* @param onFulfilled - Function called for successful requests
* @param onRejected - Function called for request errors
* @param options - Additional interceptor options
* @returns Interceptor ID for later removal
*/
axios.interceptors.request.use(
onFulfilled?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,
onRejected?: (error: any) => any,
options?: AxiosInterceptorOptions
): number;
interface AxiosInterceptorOptions {
/** Execute interceptor synchronously */
synchronous?: boolean;
/** Conditionally run interceptor based on config */
runWhen?: (config: InternalAxiosRequestConfig) => boolean;
}Usage Examples:
// Add authentication token to all requests
axios.interceptors.request.use(
(config) => {
const token = localStorage.getItem("authToken");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
console.error("Request error:", error);
return Promise.reject(error);
}
);
// Log all outgoing requests
axios.interceptors.request.use((config) => {
console.log(`Making ${config.method?.toUpperCase()} request to: ${config.url}`);
config.metadata = { startTime: Date.now() };
return config;
});
// Conditional interceptor
axios.interceptors.request.use(
(config) => {
// Add special header for admin endpoints
if (config.url?.includes("/admin/")) {
config.headers["X-Admin-Request"] = "true";
}
return config;
},
undefined,
{
runWhen: (config) => config.url?.includes("/admin/") || false
}
);Intercept responses before they are handled by the application. Useful for global error handling, data transformation, or caching.
/**
* Add a response interceptor
* @param onFulfilled - Function called for successful responses
* @param onRejected - Function called for response errors
* @returns Interceptor ID for later removal
*/
axios.interceptors.response.use(
onFulfilled?: (response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,
onRejected?: (error: any) => any
): number;Usage Examples:
// Global error handling
axios.interceptors.response.use(
(response) => {
// Log successful responses
console.log(`Received ${response.status} from ${response.config.url}`);
return response;
},
(error) => {
if (error.response?.status === 401) {
// Redirect to login on unauthorized
window.location.href = "/login";
} else if (error.response?.status >= 500) {
// Show error notification for server errors
showErrorNotification("Server error occurred");
}
return Promise.reject(error);
}
);
// Data transformation
axios.interceptors.response.use((response) => {
// Transform snake_case API responses to camelCase
if (response.data && typeof response.data === "object") {
response.data = transformKeys(response.data, camelCase);
}
return response;
});
// Response timing
axios.interceptors.response.use(
(response) => {
const startTime = response.config.metadata?.startTime;
if (startTime) {
const duration = Date.now() - startTime;
console.log(`Request to ${response.config.url} took ${duration}ms`);
}
return response;
},
(error) => {
const startTime = error.config?.metadata?.startTime;
if (startTime) {
const duration = Date.now() - startTime;
console.log(`Failed request to ${error.config?.url} took ${duration}ms`);
}
return Promise.reject(error);
}
);Manage interceptors by removing them when no longer needed.
/**
* Remove a request interceptor
* @param id - Interceptor ID returned from use()
*/
axios.interceptors.request.eject(id: number): void;
/**
* Remove a response interceptor
* @param id - Interceptor ID returned from use()
*/
axios.interceptors.response.eject(id: number): void;
/**
* Remove all request interceptors
*/
axios.interceptors.request.clear(): void;
/**
* Remove all response interceptors
*/
axios.interceptors.response.clear(): void;Usage Examples:
// Store interceptor ID for later removal
const requestInterceptorId = axios.interceptors.request.use((config) => {
// Add debugging header
config.headers["X-Debug"] = "true";
return config;
});
// Remove specific interceptor
axios.interceptors.request.eject(requestInterceptorId);
// Clear all interceptors
axios.interceptors.request.clear();
axios.interceptors.response.clear();
// Conditional cleanup
function setupInterceptors() {
if (process.env.NODE_ENV === "development") {
return axios.interceptors.request.use((config) => {
console.log("DEV REQUEST:", config);
return config;
});
}
return null;
}
function cleanupInterceptors(interceptorId) {
if (interceptorId !== null) {
axios.interceptors.request.eject(interceptorId);
}
}Each axios instance has its own interceptor managers for requests and responses.
interface AxiosInterceptorManager<V> {
/** Add new interceptor */
use: V extends AxiosResponse
? AxiosResponseInterceptorUse<V>
: AxiosRequestInterceptorUse<V>;
/** Remove interceptor by ID */
eject(id: number): void;
/** Remove all interceptors */
clear(): void;
}
// Available on any axios instance
interface AxiosInstance {
interceptors: {
request: AxiosInterceptorManager<InternalAxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
}Complex interceptor patterns for real-world applications.
Usage Examples:
// Token refresh interceptor
let isRefreshing = false;
let refreshSubscribers = [];
axios.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
// Queue requests while refreshing
return new Promise((resolve) => {
refreshSubscribers.push((token) => {
originalRequest.headers.Authorization = `Bearer ${token}`;
resolve(axios(originalRequest));
});
});
}
originalRequest._retry = true;
isRefreshing = true;
try {
const refreshToken = localStorage.getItem("refreshToken");
const response = await axios.post("/auth/refresh", { refreshToken });
const newToken = response.data.accessToken;
localStorage.setItem("authToken", newToken);
// Retry queued requests
refreshSubscribers.forEach(callback => callback(newToken));
refreshSubscribers = [];
originalRequest.headers.Authorization = `Bearer ${newToken}`;
return axios(originalRequest);
} catch (refreshError) {
// Refresh failed, redirect to login
localStorage.clear();
window.location.href = "/login";
return Promise.reject(refreshError);
} finally {
isRefreshing = false;
}
}
return Promise.reject(error);
}
);
// Request/Response correlation
const requestMap = new Map();
axios.interceptors.request.use((config) => {
const requestId = Math.random().toString(36).substr(2, 9);
config.metadata = { requestId, startTime: Date.now() };
requestMap.set(requestId, config);
return config;
});
axios.interceptors.response.use(
(response) => {
const requestId = response.config.metadata?.requestId;
if (requestId) {
requestMap.delete(requestId);
const duration = Date.now() - response.config.metadata.startTime;
console.log(`✅ ${response.config.method?.toUpperCase()} ${response.config.url} (${duration}ms)`);
}
return response;
},
(error) => {
const requestId = error.config?.metadata?.requestId;
if (requestId) {
requestMap.delete(requestId);
const duration = Date.now() - error.config.metadata.startTime;
console.log(`❌ ${error.config?.method?.toUpperCase()} ${error.config?.url} (${duration}ms)`);
}
return Promise.reject(error);
}
);
// Retry with exponential backoff
axios.interceptors.response.use(
(response) => response,
async (error) => {
const config = error.config;
if (!config || !error.response || config.__retryCount >= 3) {
return Promise.reject(error);
}
// Retry only on network errors or 5xx status codes
if (error.response.status >= 500 || error.code === "NETWORK_ERROR") {
config.__retryCount = config.__retryCount || 0;
config.__retryCount += 1;
const delay = Math.pow(2, config.__retryCount) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
return axios(config);
}
return Promise.reject(error);
}
);