@vepler/http-client
Version:
A flexible and extensible API service library for making HTTP requests with built-in authentication support for bearer tokens and API keys.
78 lines (67 loc) • 3.14 kB
text/typescript
import logger from '@vepler/logger';
import { AxiosError } from 'axios';
import { HttpError, createErrorFromResponse, TimeoutError, NetworkError, ClientError } from '../errors/http-error';
import { parseAxiosError } from '../errors/error-utils';
/**
* Response error interceptor that converts Axios errors to typed HttpError instances
* and logs them with proper context and sensitive data masking
*/
export default (error: AxiosError): Promise<never> => {
// Create typed, detailed error based on the response
let httpError: HttpError;
try {
if (error.response) {
// Server responded with an error status (4xx, 5xx)
httpError = createErrorFromResponse(error.response);
// Log error with contextual information but mask sensitive data
const errorObj = new Error(`[HTTP ${httpError.status}] ${httpError.name}: ${httpError.message}`);
logger.error(errorObj, 'HTTP Response Error', {
status: httpError.status,
endpoint: httpError.endpoint,
errorDetails: parseAxiosError(error)
});
} else if (error.code === 'ECONNABORTED') {
// Timeout error
const { url, method } = error.config || {};
httpError = new TimeoutError(
`Request timeout after ${error.config?.timeout}ms - ${method?.toUpperCase()} ${url}`,
error.request,
url,
method?.toUpperCase()
);
const timeoutError = new Error(`[TIMEOUT] ${httpError.message}`);
logger.error(timeoutError, 'Request Timeout Error', {
timeout: error.config?.timeout,
url,
method
});
} else if (error.request) {
// Request was made but no response received (network error)
const { url, method } = error.config || {};
httpError = new NetworkError(
`Network error - ${method?.toUpperCase()} ${url}`,
error.request,
url,
method?.toUpperCase()
);
const networkError = new Error(`[NETWORK] ${httpError.message}`);
logger.error(networkError, 'Network Error', {
url,
method
});
} else {
// Error in setting up the request
httpError = new ClientError(error.message || 'Request setup error');
const clientError = new Error(`[CLIENT] ${httpError.message}`);
logger.error(clientError, 'Client Error');
}
} catch (loggingError) {
// Fallback in case error parsing/logging fails
const processingError = new Error('Error while processing HTTP error');
logger.error(processingError, 'Error Processing', { loggingError });
// Still create a basic error
httpError = new HttpError(error.message || 'Unknown HTTP error');
}
// Return a rejected promise with our typed error
return Promise.reject(httpError);
};