robust-axios-client
v1.2.0
Published
A robust Axios client implementation
Downloads
27
Maintainers
Readme
robust-axios-client
A robust and feature-rich Axios client implementation with advanced resilience patterns, including retries, circuit breaker, rate limiting, and more.
Features
- 🔄 Advanced retry mechanism with multiple backoff strategies
- 🔌 Circuit breaker pattern to prevent cascading failures
- 🚦 Rate limiting with token bucket algorithm
- 📝 Comprehensive logging system with customizable loggers
- ⚠️ Sophisticated error handling and categorization
- 🔍 Debug mode for detailed request/response logging
- 🏃 Dry run capability for testing
- 🔒 Automatic sensitive data sanitization
- 🎯 Request categorization for endpoint-specific behavior
- 💪 Full TypeScript support
- 📦 Complete Axios API compatibility
Installation
npm install robust-axios-clientQuick Start
import RobustAxios from 'robust-axios-client';
const client = RobustAxios.create({
baseURL: 'https://api.example.com',
});
// Make a GET request
const response = await client.get('/users');
// Make a POST request
const user = await client.post('/users', { name: 'John Doe' });Configuration
Basic Configuration
const client = RobustAxios.create({
baseURL: 'https://api.example.com', // Required
debug: false, // Optional: enables detailed logging
dryRun: false, // Optional: simulate requests without sending them
logger: customLogger, // Optional: custom logger implementation
});Retry Configuration
const client = RobustAxios.create({
baseURL: 'https://api.example.com',
retry: {
maxRetries: 3, // Number of retry attempts
retryCondition: (error) => boolean, // Custom retry condition
retryDelay: (retryCount, error) => number, // Custom delay between retries
backoffStrategy: 'exponential', // 'exponential', 'linear', 'fibonacci', or 'custom'
customBackoff: (retryCount, error) => number, // Custom backoff function
timeoutStrategy: 'decay', // 'reset', 'decay', or 'fixed'
timeoutMultiplier: 1.5 // Used with 'decay' strategy
}
});Circuit Breaker Configuration
const client = RobustAxios.create({
baseURL: 'https://api.example.com',
retry: {
circuitBreaker: {
failureThreshold: 5, // Number of failures before opening circuit
resetTimeout: 60000, // Time in ms before attempting half-open state
halfOpenMaxRequests: 3 // Max requests to allow in half-open state
},
onCircuitBreakerStateChange: (newState) => {
console.log(`Circuit breaker state changed to: ${newState}`);
}
}
});Rate Limiting Configuration
const client = RobustAxios.create({
baseURL: 'https://api.example.com',
rateLimit: {
maxRequests: 100, // Maximum number of requests
windowMs: 60000, // Time window in milliseconds (1 minute)
}
});Custom Error Handler
const client = RobustAxios.create({
baseURL: 'https://api.example.com',
customErrorHandler: (error) => {
// Custom error handling logic
return new Error('Custom error message');
}
});Advanced Usage
Custom Logger Implementation
import { LoggerInterface } from 'robust-axios-client';
class CustomLogger implements LoggerInterface {
debug(message: string, ...args: unknown[]): void {
console.debug(message, ...args);
}
info(message: string, ...args: unknown[]): void {
console.info(message, ...args);
}
warn(message: string, ...args: unknown[]): void {
console.warn(message, ...args);
}
error(message: string, ...args: unknown[]): void {
console.error(message, ...args);
}
}
const client = RobustAxios.create({
baseURL: 'https://api.example.com',
logger: new CustomLogger(),
});Request Categorization
const client = RobustAxios.create({
baseURL: 'https://api.example.com',
retry: {
requestCategories: {
authEndpoints: {
matcher: (config) => config.url?.includes('/auth'),
settings: {
maxRetries: 1,
backoffStrategy: 'linear'
}
},
userEndpoints: {
matcher: (config) => config.url?.includes('/users'),
settings: {
maxRetries: 5,
backoffStrategy: 'exponential'
}
}
}
}
});Event Hooks
const client = RobustAxios.create({
baseURL: 'https://api.example.com',
retry: {
onRetry: (context) => {
console.log(`Retrying request. Attempt: ${context.retryCount}`);
},
onSuccess: (response, context) => {
console.log(`Request succeeded after ${context.retryCount} retries`);
},
onFailed: (error, context) => {
console.log(`Request failed after ${context.retryCount} retries`);
}
}
});API Reference
RobustAxios Methods
Static Methods
create(config: RobustAxiosConfig): RobustAxiosrequest<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>>get<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>patch<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>delete<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>head<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>options<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>getUri(config?: AxiosRequestConfig): stringall<T>(values: Array<T | Promise<T>>): Promise<T[]>spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => RisCancel(value: unknown): booleanisAxiosError(payload: unknown): payload is AxiosError
Instance Methods
request<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>>get<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>patch<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>delete<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>head<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>options<T>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>getUri(config?: AxiosRequestConfig): stringgetInstance(): AxiosInstancesetDefaultHeader(key: string, value: string): voidupdateConfig(newConfig: AxiosRequestConfig): voidaddRequestInterceptor(onFulfilled, onRejected?): numberaddResponseInterceptor(onFulfilled, onRejected?): numberremoveRequestInterceptor(interceptorId: number): voidremoveResponseInterceptor(interceptorId: number): void
Configuration Options
| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | baseURL | string | No | '' | Base URL for the API | | debug | boolean | No | false | Enable detailed logging | | dryRun | boolean | No | false | Simulate requests without sending | | logger | LoggerInterface | No | ConsoleLogger | Custom logger implementation | | retry | RetryConfig | No | Default config | Retry configuration | | customErrorHandler | Function | No | Built-in handler | Custom error handler | | rateLimit | { maxRequests: number, windowMs: number } | No | undefined | Rate limiting configuration | | ...other AxiosRequestConfig options | various | No | Axios defaults | Any valid Axios request config |
Error Handling
The client handles various error scenarios with dedicated error classes:
HttpError- For HTTP status errors with detailed response informationTimeoutError- For request timeouts (ECONNABORTED)RateLimitError- When rate limit is exceededValidationError- For validation errors
TypeScript Support
This library is written in TypeScript and includes comprehensive type definitions.
Testing
E2E Testing with Mock Service Worker
This library includes testing capabilities using Mock Service Worker (MSW) for end-to-end testing without relying on external services. This is particularly useful for testing error handling, retry mechanisms, circuit breakers, and other resilience features.
import { setupServer } from 'msw/node';
import { rest } from 'msw';
import RobustAxios from 'robust-axios-client';
// Set up the MSW server with custom handlers
const handlers = [
// Simulate a server error
rest.get('/api/users', (req, res, ctx) => {
return res(ctx.status(500), ctx.json({ message: 'Server error' }));
}),
// Simulate rate limiting
rest.get('/api/data', (req, res, ctx) => {
// Custom logic to implement rate limiting
const shouldLimit = /* your rate limiting logic */;
if (shouldLimit) {
return res(ctx.status(429), ctx.json({ message: 'Too many requests' }));
}
return res(ctx.json({ data: 'Success' }));
}),
// Simulate slow responses
rest.get('/api/slow', (req, res, ctx) => {
return res(ctx.delay(3000), ctx.json({ data: 'Delayed response' }));
}),
];
// Create and configure the server
const server = setupServer(...handlers);
// Start the server before tests
beforeAll(() => server.listen());
// Reset handlers after each test
afterEach(() => server.resetHandlers());
// Clean up after all tests
afterAll(() => server.close());
// Create a client for testing
const client = RobustAxios.create({ baseURL: 'http://localhost' });
// Test example
try {
await client.get('/api/users');
} catch (error) {
// Handle server error
}For more detailed examples of testing, see the tests in the tests/msw directory of the repository.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Author
Sergiu Savva
Support
For bugs and feature requests, please open an issue.
