Axios Interceptor Scope and Instance Isolation Limits
0 reputation · 01 Sept 2023, 06:57 UTC
0 reputation · 01 Sept 2023, 06:57 UTC
Axios provides the interceptors object to allow custom logic for request and response transformations. While global interceptors applied to the main axios instance affect all requests, the axios.create() method allows for the creation of isolated instances with their own interceptor stacks.
A design uncertainty arises when managing shared logic across multiple custom instances. If a set of common interceptors is required for several instances but specific instances need unique overrides or a different execution order, the current architecture requires manual registration for each instance.
axios.create()?33775 reputation · 01 Sept 2023, 13:05 UTC
Global interceptors do not propagate to instances created via axios.create(). Each call to axios.create() produces a brand-new AxiosInstance with its own independent interceptors.request and interceptors.response managers. There is no documented API in Axios 1.x to inherit, clone, or share an interceptor stack between instances.
axios export is a pre-configured instance. Interceptors registered on axios.interceptors.request or axios.interceptors.response only fire for requests made through that exact instance (axios(config)).axios.create(config) constructs a fresh instance. Its constructor initializes this.interceptors = { request: new InterceptorManager(), response: new InterceptorManager() } — separate arrays, no reference to the global instance's handlers.Since the library deliberately isolates instances, the standard approach is a factory that centralizes common interceptor registration:
// shared-interceptors.js
export const commonRequestInterceptors = [
(config) => { /* auth header, logging, etc. */ return config; },
(config) => { /* base URL normalization */ return config; }
];
export const commonResponseInterceptors = [
(response) => { /* normalize data shape */ return response; },
(error) => { /* global error handling */ return Promise.reject(error); }
];
// api-client-factory.js
import axios from 'axios';
import { commonRequestInterceptors, commonResponseInterceptors } from './shared-interceptors';
export function createApiClient(overrides = {}) {
const client = axios.create({
baseURL: '/api',
timeout: 10000,
...overrides
});
commonRequestInterceptors.forEach(fn => client.interceptors.request.use(fn));
commonResponseInterceptors.forEach(fn => client.interceptors.response.use(fn));
return client;
}
// Usage
const publicApi = createApiClient();
const adminApi = createApiClient({ baseURL: '/admin', headers: { 'X-Admin': 'true' } });
// Add instance-specific interceptors after creation if needed
adminApi.interceptors.request.use((config) => { /* admin-only logic */ return config; });
const a = axios.create(); const b = axios.create();axios.interceptors.request.use(() => console.log('global'))a.get('/test') and b.get('/test') — neither logs "global".axios.get('/test') — logs "global".axios.interceptors.request.handlers vs a.interceptors.request.handlers — they are distinct arrays.axios.defaults after instance creation does not affect existing instances; defaults are read at creation time.axios will not apply to custom instances unless the plugin explicitly accepts an instance parameter.interceptors arrays, not the global one.Are you using any Axios plugins or middleware (e.g., axios-retry, axios-mock-adapter) that might expect global registration? If so, the factory pattern must explicitly pass the created instance to those plugins.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.