- Spec files
npm-axios
Describes: pkg:npm/axios@1.6.x
- Description
- Promise based HTTP client for the browser and node.js
- Author
- tessl
- Last updated
interceptors.md docs/
1# Interceptors23Request and response middleware system for automatic processing, authentication, logging, error handling, and data transformation. Interceptors allow you to modify requests before they are sent and responses before they are handled.45## Capabilities67### Interceptor Manager Interface89Interface for managing request and response interceptors.1011```typescript { .api }12interface AxiosInterceptorManager<V> {13/**14* Add interceptor15* @param onFulfilled - Success handler function16* @param onRejected - Error handler function17* @param options - Interceptor options18* @returns Interceptor ID for removal19*/20use(21onFulfilled?: ((value: V) => V | Promise<V>) | null,22onRejected?: ((error: any) => any) | null,23options?: AxiosInterceptorOptions24): number;2526/**27* Remove interceptor by ID28* @param id - Interceptor ID returned by use()29*/30eject(id: number): void;3132/**33* Remove all interceptors34*/35clear(): void;36}3738interface AxiosInterceptorOptions {39/** Run interceptor synchronously */40synchronous?: boolean;4142/** Conditional execution function */43runWhen?: (config: InternalAxiosRequestConfig) => boolean;44}45```4647**Usage Examples:**4849```typescript50import axios from "axios";5152// Access interceptors from default instance53console.log(axios.interceptors.request); // Request interceptor manager54console.log(axios.interceptors.response); // Response interceptor manager5556// Access interceptors from custom instance57const api = axios.create();58console.log(api.interceptors.request);59console.log(api.interceptors.response);60```6162### Request Interceptors6364Modify requests before they are sent to the server.6566**Usage Examples:**6768```typescript69import axios from "axios";7071// Add authentication header72const authInterceptor = axios.interceptors.request.use(73(config) => {74const token = localStorage.getItem("authToken");75if (token) {76config.headers.Authorization = `Bearer ${token}`;77}78return config;79},80(error) => {81return Promise.reject(error);82}83);8485// Add request logging86const loggingInterceptor = axios.interceptors.request.use(87(config) => {88console.log(`Making ${config.method?.toUpperCase()} request to ${config.url}`);89console.log("Request config:", config);90return config;91}92);9394// Add request timing95const timingInterceptor = axios.interceptors.request.use(96(config) => {97config.metadata = { startTime: Date.now() };98return config;99}100);101102// Add request ID for tracking103const requestIdInterceptor = axios.interceptors.request.use(104(config) => {105config.headers["X-Request-ID"] = `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;106return config;107}108);109110// Conditional interceptor111const conditionalInterceptor = axios.interceptors.request.use(112(config) => {113if (config.url?.includes("/api/v2/")) {114config.headers["API-Version"] = "2.0";115}116return config;117},118null,119{120runWhen: (config) => config.url?.includes("/api/") ?? false121}122);123124// Handle request errors125const errorInterceptor = axios.interceptors.request.use(126(config) => config,127(error) => {128console.error("Request configuration error:", error);129// Could show user notification here130return Promise.reject(error);131}132);133```134135### Response Interceptors136137Process responses after they are received from the server.138139**Usage Examples:**140141```typescript142import axios from "axios";143144// Transform response data145const dataTransformInterceptor = axios.interceptors.response.use(146(response) => {147// Transform dates from strings to Date objects148if (response.data && typeof response.data === "object") {149transformDates(response.data);150}151return response;152},153(error) => {154return Promise.reject(error);155}156);157158// Add response timing159const responseTimingInterceptor = axios.interceptors.response.use(160(response) => {161const startTime = response.config.metadata?.startTime;162if (startTime) {163const duration = Date.now() - startTime;164console.log(`Request completed in ${duration}ms`);165}166return response;167}168);169170// Response logging171const responseLoggingInterceptor = axios.interceptors.response.use(172(response) => {173console.log(`Response ${response.status} from ${response.config.url}`);174console.log("Response data:", response.data);175return response;176},177(error) => {178if (error.response) {179console.error(`Error ${error.response.status} from ${error.config?.url}`);180console.error("Error data:", error.response.data);181}182return Promise.reject(error);183}184);185186// Automatic token refresh187const tokenRefreshInterceptor = axios.interceptors.response.use(188(response) => response,189async (error) => {190const originalRequest = error.config;191192if (error.response?.status === 401 && !originalRequest._retry) {193originalRequest._retry = true;194195try {196const refreshToken = localStorage.getItem("refreshToken");197const response = await axios.post("/auth/refresh", { refreshToken });198const newToken = response.data.accessToken;199200localStorage.setItem("authToken", newToken);201originalRequest.headers.Authorization = `Bearer ${newToken}`;202203return axios(originalRequest);204} catch (refreshError) {205// Refresh failed, redirect to login206localStorage.removeItem("authToken");207localStorage.removeItem("refreshToken");208window.location.href = "/login";209return Promise.reject(refreshError);210}211}212213return Promise.reject(error);214}215);216217// Error handling and user notifications218const errorHandlingInterceptor = axios.interceptors.response.use(219(response) => response,220(error) => {221if (error.response) {222const { status, data } = error.response;223224switch (status) {225case 400:226showNotification("Invalid request data", "error");227break;228case 401:229showNotification("Authentication required", "warning");230break;231case 403:232showNotification("Access denied", "error");233break;234case 404:235showNotification("Resource not found", "warning");236break;237case 500:238showNotification("Server error occurred", "error");239break;240default:241showNotification(`Request failed: ${data.message || error.message}`, "error");242}243} else if (error.request) {244showNotification("Network error - please check your connection", "error");245}246247return Promise.reject(error);248}249);250```251252### Managing Interceptors253254Add, remove, and configure interceptors dynamically.255256**Usage Examples:**257258```typescript259import axios from "axios";260261// Store interceptor IDs for later removal262const interceptorIds: number[] = [];263264// Add interceptors and store their IDs265interceptorIds.push(266axios.interceptors.request.use(config => {267console.log("Request interceptor 1");268return config;269})270);271272interceptorIds.push(273axios.interceptors.request.use(config => {274console.log("Request interceptor 2");275return config;276})277);278279interceptorIds.push(280axios.interceptors.response.use(response => {281console.log("Response interceptor 1");282return response;283})284);285286// Remove specific interceptor287axios.interceptors.request.eject(interceptorIds[0]);288289// Remove all request interceptors290axios.interceptors.request.clear();291292// Remove all response interceptors293axios.interceptors.response.clear();294295// Conditional interceptor management296class ApiClient {297private requestInterceptorId?: number;298private responseInterceptorId?: number;299300enableAuthentication(token: string) {301// Remove existing auth interceptor if any302if (this.requestInterceptorId !== undefined) {303axios.interceptors.request.eject(this.requestInterceptorId);304}305306// Add new auth interceptor307this.requestInterceptorId = axios.interceptors.request.use(308(config) => {309config.headers.Authorization = `Bearer ${token}`;310return config;311}312);313}314315disableAuthentication() {316if (this.requestInterceptorId !== undefined) {317axios.interceptors.request.eject(this.requestInterceptorId);318this.requestInterceptorId = undefined;319}320}321322enableLogging() {323this.responseInterceptorId = axios.interceptors.response.use(324(response) => {325console.log(`${response.status} ${response.config.method?.toUpperCase()} ${response.config.url}`);326return response;327}328);329}330331disableLogging() {332if (this.responseInterceptorId !== undefined) {333axios.interceptors.response.eject(this.responseInterceptorId);334this.responseInterceptorId = undefined;335}336}337}338339const client = new ApiClient();340client.enableAuthentication("token123");341client.enableLogging();342```343344### Advanced Interceptor Patterns345346Complex interceptor implementations for common use cases.347348**Usage Examples:**349350```typescript351import axios, { AxiosRequestConfig, AxiosResponse } from "axios";352353// Request/response correlation354const correlationInterceptor = {355request: axios.interceptors.request.use((config) => {356const correlationId = `corr-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;357config.headers["X-Correlation-ID"] = correlationId;358config.metadata = { ...config.metadata, correlationId };359return config;360}),361362response: axios.interceptors.response.use(363(response) => {364const correlationId = response.config.metadata?.correlationId;365console.log(`Response received for correlation ID: ${correlationId}`);366return response;367},368(error) => {369const correlationId = error.config?.metadata?.correlationId;370console.error(`Error for correlation ID: ${correlationId}`, error);371return Promise.reject(error);372}373)374};375376// Retry mechanism with exponential backoff377function createRetryInterceptor(maxRetries = 3, baseDelay = 1000) {378return axios.interceptors.response.use(379(response) => response,380async (error) => {381const config = error.config;382383// Don't retry if we've exceeded max retries384if (config.__retryCount >= maxRetries) {385return Promise.reject(error);386}387388// Don't retry client errors (4xx) except 429389if (error.response?.status >= 400 && error.response?.status < 500 && error.response?.status !== 429) {390return Promise.reject(error);391}392393// Initialize retry count394config.__retryCount = config.__retryCount || 0;395config.__retryCount += 1;396397// Calculate delay with exponential backoff398const delay = baseDelay * Math.pow(2, config.__retryCount - 1);399400console.log(`Retrying request (attempt ${config.__retryCount}/${maxRetries}) after ${delay}ms delay`);401402// Wait before retrying403await new Promise(resolve => setTimeout(resolve, delay));404405// Retry the request406return axios(config);407}408);409}410411// Enable retry interceptor412const retryInterceptorId = createRetryInterceptor(3, 1000);413414// Caching interceptor415const cache = new Map<string, { data: any; timestamp: number; ttl: number }>();416417function createCacheInterceptor(defaultTtl = 5 * 60 * 1000) { // 5 minutes418return {419request: axios.interceptors.request.use((config) => {420// Only cache GET requests421if (config.method?.toLowerCase() === "get") {422const cacheKey = `${config.method}:${config.url}:${JSON.stringify(config.params)}`;423const cached = cache.get(cacheKey);424425if (cached && Date.now() - cached.timestamp < cached.ttl) {426console.log("Returning cached response for:", cacheKey);427// Return cached response wrapped in a resolved promise428config.__cached = true;429config.__cachedResponse = {430data: cached.data,431status: 200,432statusText: "OK (cached)",433headers: {},434config,435request: {}436};437}438}439return config;440}),441442response: axios.interceptors.response.use((response) => {443// If this was a cached response, return it444if (response.config.__cached) {445return response.config.__cachedResponse;446}447448// Cache GET responses449if (response.config.method?.toLowerCase() === "get" && response.status === 200) {450const cacheKey = `${response.config.method}:${response.config.url}:${JSON.stringify(response.config.params)}`;451const ttl = response.headers["cache-control"]?.includes("max-age=")452? parseInt(response.headers["cache-control"].match(/max-age=(\d+)/)?.[1] || "0") * 1000453: defaultTtl;454455cache.set(cacheKey, {456data: response.data,457timestamp: Date.now(),458ttl459});460461console.log("Cached response for:", cacheKey);462}463464return response;465})466};467}468469// Enable caching470const cacheInterceptor = createCacheInterceptor();471```472473### Instance-Specific Interceptors474475Use interceptors with specific axios instances for isolated behavior.476477**Usage Examples:**478479```typescript480import axios from "axios";481482// Create specialized API clients483const apiV1 = axios.create({ baseURL: "https://api.example.com/v1" });484const apiV2 = axios.create({ baseURL: "https://api.example.com/v2" });485486// Different auth for different APIs487apiV1.interceptors.request.use((config) => {488config.headers.Authorization = `Bearer ${getV1Token()}`;489return config;490});491492apiV2.interceptors.request.use((config) => {493config.headers.Authorization = `Bearer ${getV2Token()}`;494config.headers["API-Version"] = "2.0";495return config;496});497498// Different error handling for different APIs499apiV1.interceptors.response.use(500(response) => response,501(error) => {502console.log("API v1 error:", error);503return Promise.reject(error);504}505);506507apiV2.interceptors.response.use(508(response) => response,509(error) => {510console.log("API v2 error:", error);511// V2 might have different error format512if (error.response?.data?.errors) {513error.message = error.response.data.errors.join(", ");514}515return Promise.reject(error);516}517);518519// Use different instances520const v1Users = await apiV1.get("/users");521const v2Users = await apiV2.get("/users");522```