npm package: @mirawision/apium
Description: Advanced API management library for TypeScript with request/response interceptors, caching, retry logic, and comprehensive error handling.
Author: Yelysei Lukin
Latest version: 1.0.1

# @mirawision/apium

Advanced API management library for TypeScript with request/response interceptors, caching, retry logic, and comprehensive error handling. Apium provides a powerful and flexible way to manage HTTP requests with built-in features for modern web applications.

## Features

- **Request/Response Interceptors**: Modify requests and responses globally or per-instance
- **Automatic Retry Logic**: Configurable retry strategies with exponential backoff
- **Caching System**: Built-in caching with TTL and cache invalidation
- **Type Safety**: Full TypeScript support with generic request/response types
- **Error Handling**: Comprehensive error handling with custom error types
- **Request Cancellation**: Support for request cancellation and timeouts
- **Progress Tracking**: Upload/download progress tracking
- **Middleware Support**: Chain multiple interceptors and middleware
- **Flexible Configuration**: Extensive configuration options for all features

## Installation

```bash
npm install @mirawision/apium
```

or 

```bash
yarn add @mirawision/apium
```

## Usage

### Basic Example

```typescript
import { Apium, RequestConfig, Response } from '@mirawision/apium';

interface User {
  id: number;
  name: string;
  email: string;
}

interface CreateUserRequest {
  name: string;
  email: string;
}

const api = new Apium({
  baseURL: 'https://api.example.com',
  timeout: 5000,
  retries: 3
});

// GET request
const users: User[] = await api.get<User[]>('/users');

// POST request
const newUser: User = await api.post<User, CreateUserRequest>('/users', {
  name: 'John Doe',
  email: 'john@example.com'
});

// PUT request
const updatedUser: User = await api.put<User, Partial<User>>('/users/1', {
  name: 'Jane Doe'
});

// DELETE request
await api.delete('/users/1');
```

### Request/Response Interceptors

```typescript
import { Apium, RequestInterceptor, ResponseInterceptor } from '@mirawision/apium';

const api = new Apium({
  baseURL: 'https://api.example.com'
});

// Request interceptor - add auth header
api.addRequestInterceptor((config) => {
  config.headers = {
    ...config.headers,
    'Authorization': `Bearer ${localStorage.getItem('token')}`
  };
  return config;
});

// Response interceptor - handle errors globally
api.addResponseInterceptor(
  (response) => {
    // Handle successful responses
    return response;
  },
  (error) => {
    if (error.status === 401) {
      // Handle unauthorized access
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

// Per-request interceptor
const userResponse = await api.get<User>('/users/1', {
  interceptors: {
    request: (config) => {
      console.log('Making request to:', config.url);
      return config;
    },
    response: (response) => {
      console.log('Received response:', response.data);
      return response;
    }
  }
});
```

### Retry Logic

```typescript
import { Apium, RetryConfig } from '@mirawision/apium';

const api = new Apium({
  baseURL: 'https://api.example.com',
  retries: 3,
  retryDelay: 1000,
  retryCondition: (error) => {
    // Retry on network errors or 5xx status codes
    return error.isNetworkError || (error.status >= 500 && error.status < 600);
  }
});

// Custom retry for specific request
const response = await api.get<User>('/users/1', {
  retries: 5,
  retryDelay: 2000,
  retryCondition: (error) => error.status === 429 // Rate limit
});
```

### Caching

```typescript
import { Apium, CacheConfig } from '@mirawision/apium';

const api = new Apium({
  baseURL: 'https://api.example.com',
  cache: {
    enabled: true,
    ttl: 5 * 60 * 1000, // 5 minutes
    maxSize: 100
  }
});

// Cache specific request
const users = await api.get<User[]>('/users', {
  cache: {
    key: 'users-list',
    ttl: 10 * 60 * 1000 // 10 minutes
  }
});

// Invalidate cache
api.invalidateCache('users-list');
api.clearCache(); // Clear all cache
```

### Error Handling

```typescript
import { Apium, ApiError } from '@mirawision/apium';

const api = new Apium({
  baseURL: 'https://api.example.com'
});

try {
  const user = await api.get<User>('/users/1');
} catch (error) {
  if (error instanceof ApiError) {
    switch (error.status) {
      case 404:
        console.log('User not found');
        break;
      case 500:
        console.log('Server error');
        break;
      default:
        console.log('Unknown error:', error.message);
    }
  }
}
```

### Request Cancellation

```typescript
import { Apium, AbortController } from '@mirawision/apium';

const api = new Apium({
  baseURL: 'https://api.example.com'
});

const controller = new AbortController();

// Start request
const request = api.get<User>('/users/1', {
  signal: controller.signal
});

// Cancel request after 5 seconds
setTimeout(() => {
  controller.abort();
}, 5000);

try {
  const user = await request;
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Request was cancelled');
  }
}
```

### Progress Tracking

```typescript
import { Apium } from '@mirawision/apium';

const api = new Apium({
  baseURL: 'https://api.example.com'
});

// Upload with progress
const uploadResponse = await api.post<Response, FormData>('/upload', formData, {
  onUploadProgress: (progressEvent) => {
    const percentCompleted = Math.round(
      (progressEvent.loaded * 100) / progressEvent.total
    );
    console.log(`Upload progress: ${percentCompleted}%`);
  }
});

// Download with progress
const downloadResponse = await api.get<Blob>('/download', {
  responseType: 'blob',
  onDownloadProgress: (progressEvent) => {
    const percentCompleted = Math.round(
      (progressEvent.loaded * 100) / progressEvent.total
    );
    console.log(`Download progress: ${percentCompleted}%`);
  }
});
```

### Advanced Configuration

```typescript
import { Apium, RequestConfig } from '@mirawision/apium';

const api = new Apium({
  baseURL: 'https://api.example.com',
  timeout: 10000,
  retries: 3,
  retryDelay: 1000,
  cache: {
    enabled: true,
    ttl: 5 * 60 * 1000,
    maxSize: 100
  },
  headers: {
    'Content-Type': 'application/json',
    'User-Agent': 'MyApp/1.0'
  },
  validateStatus: (status) => status < 500, // Only retry on 5xx errors
  transformRequest: (data) => {
    // Transform request data
    return JSON.stringify(data);
  },
  transformResponse: (data) => {
    // Transform response data
    return JSON.parse(data);
  }
});

// Instance-specific configuration
const userApi = new Apium({
  baseURL: 'https://api.example.com/users',
  timeout: 5000,
  headers: {
    'Authorization': `Bearer ${token}`
  }
});
```

## API Reference

### Apium Class

Main API client class for making HTTP requests.

#### Constructor

```typescript
constructor(config?: ApiumConfig)
```

#### Methods

- `get<T>(url: string, config?: RequestConfig): Promise<T>`
  - Makes a GET request

- `post<T, D = any>(url: string, data?: D, config?: RequestConfig): Promise<T>`
  - Makes a POST request

- `put<T, D = any>(url: string, data?: D, config?: RequestConfig): Promise<T>`
  - Makes a PUT request

- `patch<T, D = any>(url: string, data?: D, config?: RequestConfig): Promise<T>`
  - Makes a PATCH request

- `delete<T>(url: string, config?: RequestConfig): Promise<T>`
  - Makes a DELETE request

- `addRequestInterceptor(interceptor: RequestInterceptor): void`
  - Adds a request interceptor

- `addResponseInterceptor(interceptor: ResponseInterceptor): void`
  - Adds a response interceptor

- `invalidateCache(key?: string): void`
  - Invalidates cache entries

- `clearCache(): void`
  - Clears all cache entries

#### Type Definitions

```typescript
interface ApiumConfig {
  baseURL?: string;
  timeout?: number;
  retries?: number;
  retryDelay?: number;
  retryCondition?: (error: ApiError) => boolean;
  cache?: CacheConfig;
  headers?: Record<string, string>;
  validateStatus?: (status: number) => boolean;
  transformRequest?: (data: any) => any;
  transformResponse?: (data: any) => any;
}

interface RequestConfig {
  params?: Record<string, any>;
  headers?: Record<string, string>;
  timeout?: number;
  retries?: number;
  retryDelay?: number;
  retryCondition?: (error: ApiError) => boolean;
  cache?: CacheConfig;
  signal?: AbortSignal;
  onUploadProgress?: (progressEvent: ProgressEvent) => void;
  onDownloadProgress?: (progressEvent: ProgressEvent) => void;
  interceptors?: {
    request?: RequestInterceptor;
    response?: ResponseInterceptor;
  };
}

interface CacheConfig {
  enabled?: boolean;
  key?: string;
  ttl?: number;
  maxSize?: number;
}

interface ApiError extends Error {
  status: number;
  statusText: string;
  isNetworkError: boolean;
  config: RequestConfig;
  response?: Response;
}
```

## Contributing

Contributions are always welcome! Feel free to open issues or submit pull requests.

## License

This project is licensed under the MIT License.