Modular Axios Factory in Enterprise Codebases
This article demonstrates how to construct a modular Axios HTTP client factory for enterprise-grade TypeScript and JavaScript codebases. You will learn the syntax for building extensible instance factories, structuring reusable request and response interceptors, isolating domain-specific configurations, and enforcing consistent error handling across scalable architectures.
The Factory Function Pattern
In enterprise environments, hardcoding a single global Axios instance
leads to configuration collisions between microservices, authentication
scopes, and API gateways. An Axios client factory encapsulates
axios.create() inside a configurable higher-order function,
returning distinct instances tailored to specific service
boundaries.
import axios, { AxiosInstance, CreateAxiosDefaults } from 'axios';
export interface HttpClientConfig extends CreateAxiosDefaults {
serviceName?: string;
enableRetry?: boolean;
}
export function createHttpClient(config: HttpClientConfig = {}): AxiosInstance {
const { serviceName = 'CoreService', enableRetry = false, ...axiosConfig } = config;
const instance = axios.create({
timeout: 10000,
headers: {
'Content-Type': 'application/json',
'X-Service-Name': serviceName,
},
...axiosConfig,
});
attachInterceptors(instance);
return instance;
}Attaching Modular Interceptors
Enterprise architectures require decoupled interceptor logic for tasks such as authorization header injection, request tracing, and standardized error normalization. Separate interceptor registration into dedicated modules rather than defining them inline.
import { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from 'axios';
function requestAuthInterceptor(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig {
const token = getAuthToken(); // Retrieve from secure storage/cache
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}
function responseErrorInterceptor(error: AxiosError): Promise<never> {
const standardizedError = {
status: error.response?.status ?? 500,
message: error.response?.data || error.message,
timestamp: new Date().toISOString(),
};
// Log error to telemetry service (e.g., Datadog, Sentry)
console.error('[API Error]', standardizedError);
return Promise.reject(standardizedError);
}
export function attachInterceptors(client: AxiosInstance): void {
client.interceptors.request.use(requestAuthInterceptor, (error) => Promise.reject(error));
client.interceptors.response.use((response) => response, responseErrorInterceptor);
}
function getAuthToken(): string | null {
return process.env.API_SECRET_TOKEN || null;
}Domain-Specific Client Composition
Once the core factory is established, export domain-specific preconfigured instances. This guarantees that different external or internal APIs utilize isolated configurations while sharing the same underlying patterns.
// Payment API client instance
export const paymentClient = createHttpClient({
baseURL: process.env.PAYMENT_API_URL || 'https://payments.internal.api/v1',
serviceName: 'PaymentService',
timeout: 5000,
});
// User Management API client instance
export const userClient = createHttpClient({
baseURL: process.env.USER_API_URL || 'https://users.internal.api/v1',
serviceName: 'UserService',
timeout: 15000,
});Creating Generic API Services
Wrap the modular clients within typed service classes or object modules to ensure predictable data contracts across the application.
interface User {
id: string;
email: string;
}
export class UserService {
constructor(private readonly http: AxiosInstance = userClient) {}
async getUserById(id: string): Promise<User> {
const response = await this.http.get<User>(`/users/${id}`);
return response.data;
}
async createUser(payload: Omit<User, 'id'>): Promise<User> {
const response = await this.http.post<User>('/users', payload);
return response.data;
}
}This factory architecture maintains strict separation of concerns, improves unit testability by allowing mock instance injections, and standardizes networking patterns throughout large enterprise repositories.