import axios, { AxiosInstance, AxiosRequestConfig, AxiosError } from "axios"; import { RequestAdapter } from "./index"; import { ApiRequest, ApiResponse, ApiError, ApiClientConfig, ERROR_CLASSIFICATIONS, } from "../utils"; export class AxiosAdapter implements RequestAdapter { private instance: AxiosInstance | null = null; public initialize(config: ApiClientConfig): void { this.instance = axios.create({ baseURL: config.baseUrl, headers: config.defaultHeaders, timeout: config.requestOptions.timeout, validateStatus: (status) => status >= 200 && status < 300, }); } public async execute(request: ApiRequest): Promise { if (!this.instance) { throw new Error("AxiosAdapter not initialized. Call initialize() first."); } const { url, method, data, params, headers, options } = request; const axiosConfig: AxiosRequestConfig = { url: url, method: method, data: data, params: params, headers: headers, timeout: options.timeout, }; if (options.cancelToken?.promise) { const controller = new AbortController(); axiosConfig.signal = controller.signal; options.cancelToken.promise.then(() => { controller.abort(); }); } const startTime = Date.now(); try { const response = await this.instance.request(axiosConfig); return { data: response.data, status: response.status, statusText: response.statusText, headers: response.headers as Record, config: request, requestTime: Date.now() - startTime, }; } catch (error: any) { throw this.normalizeError(error, request); } } private normalizeError(error: any, request: ApiRequest): ApiError { const apiError: Partial = { name: "ApiRequestError", message: error.message || "Unknown Axios Error", request: request, classification: ERROR_CLASSIFICATIONS.UNKNOWN, }; if (axios.isAxiosError(error)) { const axiosError = error as AxiosError; if (axiosError.response) { apiError.response = { data: axiosError.response.data, status: axiosError.response.status, statusText: axiosError.response.statusText, headers: axiosError.response.headers as Record, config: request, requestTime: 0, }; const status = axiosError.response.status; if (status >= 500) { apiError.classification = ERROR_CLASSIFICATIONS.SERVER_ERROR; apiError.isServerError = true; } else if (status === 429) { apiError.classification = ERROR_CLASSIFICATIONS.TOO_MANY_REQUESTS; apiError.isRateLimitError = true; } else if (status >= 400) { apiError.classification = ERROR_CLASSIFICATIONS.CLIENT_ERROR; apiError.isClientError = true; } } else if (axiosError.request) { apiError.classification = ERROR_CLASSIFICATIONS.NETWORK_FAIL; apiError.isNetworkError = true; apiError.message = "Network Error: No response received"; } if ( axiosError.code === "ECONNABORTED" || axiosError.message.includes("timeout") ) { apiError.classification = ERROR_CLASSIFICATIONS.TIMEOUT_REACHED; apiError.isTimeoutError = true; } if (axios.isCancel(error)) { apiError.message = "Request canceled by user"; } } return apiError as ApiError; } }