- Spec files
npm-axios
Describes: pkg:npm/axios@1.11.x
- Description
- Promise based HTTP client for the browser and node.js
- Author
- tessl
- Last updated
interceptors.md docs/
1# Interceptors23Intercept requests and responses to transform data, add authentication, handle errors, implement retry logic, or add logging before they are handled by `then` or `catch`.45## Capabilities67### Request Interceptors89Intercept requests before they are sent to the server. Useful for adding authentication tokens, logging, or modifying request data.1011```javascript { .api }12/**13* Add a request interceptor14* @param onFulfilled - Function called for successful requests15* @param onRejected - Function called for request errors16* @param options - Additional interceptor options17* @returns Interceptor ID for later removal18*/19axios.interceptors.request.use(20onFulfilled?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>,21onRejected?: (error: any) => any,22options?: AxiosInterceptorOptions23): number;2425interface AxiosInterceptorOptions {26/** Execute interceptor synchronously */27synchronous?: boolean;28/** Conditionally run interceptor based on config */29runWhen?: (config: InternalAxiosRequestConfig) => boolean;30}31```3233**Usage Examples:**3435```javascript36// Add authentication token to all requests37axios.interceptors.request.use(38(config) => {39const token = localStorage.getItem("authToken");40if (token) {41config.headers.Authorization = `Bearer ${token}`;42}43return config;44},45(error) => {46console.error("Request error:", error);47return Promise.reject(error);48}49);5051// Log all outgoing requests52axios.interceptors.request.use((config) => {53console.log(`Making ${config.method?.toUpperCase()} request to: ${config.url}`);54config.metadata = { startTime: Date.now() };55return config;56});5758// Conditional interceptor59axios.interceptors.request.use(60(config) => {61// Add special header for admin endpoints62if (config.url?.includes("/admin/")) {63config.headers["X-Admin-Request"] = "true";64}65return config;66},67undefined,68{69runWhen: (config) => config.url?.includes("/admin/") || false70}71);72```7374### Response Interceptors7576Intercept responses before they are handled by the application. Useful for global error handling, data transformation, or caching.7778```javascript { .api }79/**80* Add a response interceptor81* @param onFulfilled - Function called for successful responses82* @param onRejected - Function called for response errors83* @returns Interceptor ID for later removal84*/85axios.interceptors.response.use(86onFulfilled?: (response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,87onRejected?: (error: any) => any88): number;89```9091**Usage Examples:**9293```javascript94// Global error handling95axios.interceptors.response.use(96(response) => {97// Log successful responses98console.log(`Received ${response.status} from ${response.config.url}`);99return response;100},101(error) => {102if (error.response?.status === 401) {103// Redirect to login on unauthorized104window.location.href = "/login";105} else if (error.response?.status >= 500) {106// Show error notification for server errors107showErrorNotification("Server error occurred");108}109return Promise.reject(error);110}111);112113// Data transformation114axios.interceptors.response.use((response) => {115// Transform snake_case API responses to camelCase116if (response.data && typeof response.data === "object") {117response.data = transformKeys(response.data, camelCase);118}119return response;120});121122// Response timing123axios.interceptors.response.use(124(response) => {125const startTime = response.config.metadata?.startTime;126if (startTime) {127const duration = Date.now() - startTime;128console.log(`Request to ${response.config.url} took ${duration}ms`);129}130return response;131},132(error) => {133const startTime = error.config?.metadata?.startTime;134if (startTime) {135const duration = Date.now() - startTime;136console.log(`Failed request to ${error.config?.url} took ${duration}ms`);137}138return Promise.reject(error);139}140);141```142143### Interceptor Management144145Manage interceptors by removing them when no longer needed.146147```javascript { .api }148/**149* Remove a request interceptor150* @param id - Interceptor ID returned from use()151*/152axios.interceptors.request.eject(id: number): void;153154/**155* Remove a response interceptor156* @param id - Interceptor ID returned from use()157*/158axios.interceptors.response.eject(id: number): void;159160/**161* Remove all request interceptors162*/163axios.interceptors.request.clear(): void;164165/**166* Remove all response interceptors167*/168axios.interceptors.response.clear(): void;169```170171**Usage Examples:**172173```javascript174// Store interceptor ID for later removal175const requestInterceptorId = axios.interceptors.request.use((config) => {176// Add debugging header177config.headers["X-Debug"] = "true";178return config;179});180181// Remove specific interceptor182axios.interceptors.request.eject(requestInterceptorId);183184// Clear all interceptors185axios.interceptors.request.clear();186axios.interceptors.response.clear();187188// Conditional cleanup189function setupInterceptors() {190if (process.env.NODE_ENV === "development") {191return axios.interceptors.request.use((config) => {192console.log("DEV REQUEST:", config);193return config;194});195}196return null;197}198199function cleanupInterceptors(interceptorId) {200if (interceptorId !== null) {201axios.interceptors.request.eject(interceptorId);202}203}204```205206### Interceptor Manager Interface207208Each axios instance has its own interceptor managers for requests and responses.209210```javascript { .api }211interface AxiosInterceptorManager<V> {212/** Add new interceptor */213use: V extends AxiosResponse214? AxiosResponseInterceptorUse<V>215: AxiosRequestInterceptorUse<V>;216/** Remove interceptor by ID */217eject(id: number): void;218/** Remove all interceptors */219clear(): void;220}221222// Available on any axios instance223interface AxiosInstance {224interceptors: {225request: AxiosInterceptorManager<InternalAxiosRequestConfig>;226response: AxiosInterceptorManager<AxiosResponse>;227};228}229```230231### Advanced Interceptor Patterns232233Complex interceptor patterns for real-world applications.234235**Usage Examples:**236237```javascript238// Token refresh interceptor239let isRefreshing = false;240let refreshSubscribers = [];241242axios.interceptors.response.use(243(response) => response,244async (error) => {245const originalRequest = error.config;246247if (error.response?.status === 401 && !originalRequest._retry) {248if (isRefreshing) {249// Queue requests while refreshing250return new Promise((resolve) => {251refreshSubscribers.push((token) => {252originalRequest.headers.Authorization = `Bearer ${token}`;253resolve(axios(originalRequest));254});255});256}257258originalRequest._retry = true;259isRefreshing = true;260261try {262const refreshToken = localStorage.getItem("refreshToken");263const response = await axios.post("/auth/refresh", { refreshToken });264const newToken = response.data.accessToken;265266localStorage.setItem("authToken", newToken);267268// Retry queued requests269refreshSubscribers.forEach(callback => callback(newToken));270refreshSubscribers = [];271272originalRequest.headers.Authorization = `Bearer ${newToken}`;273return axios(originalRequest);274} catch (refreshError) {275// Refresh failed, redirect to login276localStorage.clear();277window.location.href = "/login";278return Promise.reject(refreshError);279} finally {280isRefreshing = false;281}282}283284return Promise.reject(error);285}286);287288// Request/Response correlation289const requestMap = new Map();290291axios.interceptors.request.use((config) => {292const requestId = Math.random().toString(36).substr(2, 9);293config.metadata = { requestId, startTime: Date.now() };294requestMap.set(requestId, config);295return config;296});297298axios.interceptors.response.use(299(response) => {300const requestId = response.config.metadata?.requestId;301if (requestId) {302requestMap.delete(requestId);303const duration = Date.now() - response.config.metadata.startTime;304console.log(`✅ ${response.config.method?.toUpperCase()} ${response.config.url} (${duration}ms)`);305}306return response;307},308(error) => {309const requestId = error.config?.metadata?.requestId;310if (requestId) {311requestMap.delete(requestId);312const duration = Date.now() - error.config.metadata.startTime;313console.log(`❌ ${error.config?.method?.toUpperCase()} ${error.config?.url} (${duration}ms)`);314}315return Promise.reject(error);316}317);318319// Retry with exponential backoff320axios.interceptors.response.use(321(response) => response,322async (error) => {323const config = error.config;324325if (!config || !error.response || config.__retryCount >= 3) {326return Promise.reject(error);327}328329// Retry only on network errors or 5xx status codes330if (error.response.status >= 500 || error.code === "NETWORK_ERROR") {331config.__retryCount = config.__retryCount || 0;332config.__retryCount += 1;333334const delay = Math.pow(2, config.__retryCount) * 1000; // Exponential backoff335await new Promise(resolve => setTimeout(resolve, delay));336337return axios(config);338}339340return Promise.reject(error);341}342);343```