| # API Helper Utilities | |
| ## Overview | |
| The `APIHelper` class provides a comprehensive set of utilities for making API requests, handling authentication, and managing common operations across the application. | |
| ## Features | |
| - β **Token Management**: Automatic JWT expiration checking | |
| - β **API Requests**: Simplified fetch with error handling | |
| - β **Data Extraction**: Smart array extraction from various response formats | |
| - β **Health Monitoring**: Periodic API health checks | |
| - β **UI Helpers**: Toast notifications, formatting utilities | |
| - β **Performance**: Debounce and throttle functions | |
| --- | |
| ## Usage | |
| ### Basic Import | |
| ```javascript | |
| import { APIHelper } from '../../shared/js/utils/api-helper.js'; | |
| ``` | |
| --- | |
| ## API Methods | |
| ### Authentication | |
| #### `getHeaders()` | |
| Returns headers with optional Authorization token. Automatically checks token expiration. | |
| ```javascript | |
| const headers = APIHelper.getHeaders(); | |
| // Returns: { 'Content-Type': 'application/json', 'Authorization': 'Bearer <token>' } | |
| ``` | |
| #### `isTokenExpired(token)` | |
| Checks if a JWT token is expired. | |
| ```javascript | |
| const expired = APIHelper.isTokenExpired(token); | |
| // Returns: boolean | |
| ``` | |
| --- | |
| ### API Requests | |
| #### `fetchAPI(url, options)` | |
| Fetch data with automatic authorization and error handling. | |
| ```javascript | |
| // GET request | |
| const data = await APIHelper.fetchAPI('/api/market/top?limit=10'); | |
| // POST request | |
| const result = await APIHelper.fetchAPI('/api/sentiment/analyze', { | |
| method: 'POST', | |
| body: JSON.stringify({ text: 'Bitcoin is great!' }) | |
| }); | |
| ``` | |
| --- | |
| ### Data Processing | |
| #### `extractArray(data, keys)` | |
| Intelligently extract arrays from various response formats. | |
| ```javascript | |
| // Works with direct arrays | |
| const arr1 = APIHelper.extractArray([1, 2, 3]); | |
| // Works with nested data | |
| const arr2 = APIHelper.extractArray({ markets: [...] }, ['markets', 'data']); | |
| // Works with objects | |
| const arr3 = APIHelper.extractArray({ item1: {}, item2: {} }); | |
| ``` | |
| --- | |
| ### Health Monitoring | |
| #### `checkHealth()` | |
| Check API health status. | |
| ```javascript | |
| const health = await APIHelper.checkHealth(); | |
| // Returns: { status: 'online', healthy: true, data: {...} } | |
| ``` | |
| #### `monitorHealth(callback, interval)` | |
| Setup periodic health monitoring. | |
| ```javascript | |
| const intervalId = APIHelper.monitorHealth((health) => { | |
| console.log('API Status:', health.status); | |
| if (!health.healthy) { | |
| console.warn('API is down!'); | |
| } | |
| }, 30000); // Check every 30 seconds | |
| // Later, stop monitoring | |
| clearInterval(intervalId); | |
| ``` | |
| --- | |
| ### UI Utilities | |
| #### `showToast(message, type, duration)` | |
| Display toast notifications. | |
| ```javascript | |
| APIHelper.showToast('Operation successful!', 'success'); | |
| APIHelper.showToast('Something went wrong', 'error'); | |
| APIHelper.showToast('Please wait...', 'info'); | |
| APIHelper.showToast('Check your input', 'warning'); | |
| ``` | |
| #### `formatCurrency(amount, currency)` | |
| Format numbers as currency. | |
| ```javascript | |
| const formatted = APIHelper.formatCurrency(1234.56); | |
| // Returns: "$1,234.56" | |
| ``` | |
| #### `formatPercentage(value, decimals)` | |
| Format values as percentages. | |
| ```javascript | |
| const percent = APIHelper.formatPercentage(2.5); | |
| // Returns: "+2.50%" | |
| ``` | |
| #### `formatNumber(num, options)` | |
| Format numbers with locale settings. | |
| ```javascript | |
| const formatted = APIHelper.formatNumber(1000000); | |
| // Returns: "1,000,000" | |
| ``` | |
| --- | |
| ### Performance Utilities | |
| #### `debounce(func, wait)` | |
| Debounce function calls. | |
| ```javascript | |
| const debouncedSearch = APIHelper.debounce((query) => { | |
| console.log('Searching:', query); | |
| }, 300); | |
| // Call multiple times, only executes once after 300ms | |
| debouncedSearch('bitcoin'); | |
| debouncedSearch('ethereum'); | |
| debouncedSearch('solana'); | |
| ``` | |
| #### `throttle(func, limit)` | |
| Throttle function calls. | |
| ```javascript | |
| const throttledScroll = APIHelper.throttle(() => { | |
| console.log('Scroll event'); | |
| }, 100); | |
| window.addEventListener('scroll', throttledScroll); | |
| ``` | |
| --- | |
| ## Complete Example: Building a Page | |
| ```javascript | |
| import { APIHelper } from '../../shared/js/utils/api-helper.js'; | |
| class YourPage { | |
| constructor() { | |
| this.data = []; | |
| this.healthMonitor = null; | |
| } | |
| async init() { | |
| // Setup health monitoring | |
| this.healthMonitor = APIHelper.monitorHealth((health) => { | |
| console.log('API Health:', health.status); | |
| }); | |
| // Load data | |
| await this.loadData(); | |
| // Setup event listeners | |
| this.bindEvents(); | |
| } | |
| async loadData() { | |
| try { | |
| // Fetch data using APIHelper | |
| const response = await APIHelper.fetchAPI('/api/your-endpoint'); | |
| // Extract array safely | |
| this.data = APIHelper.extractArray(response, ['data', 'items']); | |
| // Render | |
| this.render(); | |
| // Show success | |
| APIHelper.showToast('Data loaded successfully!', 'success'); | |
| } catch (error) { | |
| console.error('Load error:', error); | |
| // Use fallback data | |
| this.data = this.getDemoData(); | |
| this.render(); | |
| // Show error | |
| APIHelper.showToast('Using demo data', 'warning'); | |
| } | |
| } | |
| bindEvents() { | |
| // Debounced search | |
| const searchInput = document.getElementById('search'); | |
| const debouncedSearch = APIHelper.debounce((query) => { | |
| this.filterData(query); | |
| }, 300); | |
| searchInput?.addEventListener('input', (e) => { | |
| debouncedSearch(e.target.value); | |
| }); | |
| } | |
| render() { | |
| // Render your data | |
| this.data.forEach(item => { | |
| const price = APIHelper.formatCurrency(item.price); | |
| const change = APIHelper.formatPercentage(item.change); | |
| console.log(`${item.name}: ${price} (${change})`); | |
| }); | |
| } | |
| getDemoData() { | |
| return [ | |
| { name: 'Bitcoin', price: 50000, change: 2.5 }, | |
| { name: 'Ethereum', price: 3000, change: -1.2 } | |
| ]; | |
| } | |
| destroy() { | |
| // Cleanup | |
| if (this.healthMonitor) { | |
| clearInterval(this.healthMonitor); | |
| } | |
| } | |
| } | |
| // Initialize | |
| const page = new YourPage(); | |
| page.init(); | |
| ``` | |
| --- | |
| ## Best Practices | |
| ### 1. Always Use APIHelper for Fetch Requests | |
| ```javascript | |
| // β Good | |
| const data = await APIHelper.fetchAPI('/api/endpoint'); | |
| // β Avoid | |
| const response = await fetch('/api/endpoint'); | |
| const data = await response.json(); | |
| ``` | |
| ### 2. Extract Arrays Safely | |
| ```javascript | |
| // β Good | |
| const items = APIHelper.extractArray(response, ['items', 'data']); | |
| // β Avoid (can fail) | |
| const items = response.items; | |
| ``` | |
| ### 3. Use Debounce for User Input | |
| ```javascript | |
| // β Good | |
| const debouncedHandler = APIHelper.debounce(handler, 300); | |
| input.addEventListener('input', debouncedHandler); | |
| // β Avoid (too many calls) | |
| input.addEventListener('input', handler); | |
| ``` | |
| ### 4. Monitor API Health | |
| ```javascript | |
| // β Good | |
| APIHelper.monitorHealth((health) => { | |
| updateUI(health.status); | |
| }); | |
| // β Avoid (no health awareness) | |
| // Just hope the API is up | |
| ``` | |
| --- | |
| ## Token Expiration | |
| The `APIHelper` automatically checks JWT token expiration: | |
| 1. **On Every Request**: Before adding Authorization header | |
| 2. **Automatic Removal**: Expired tokens are removed from localStorage | |
| 3. **Graceful Degradation**: Requests continue without auth if token expired | |
| ```javascript | |
| // Token is checked automatically | |
| const data = await APIHelper.fetchAPI('/api/protected-route'); | |
| // If token expired, it's removed and request proceeds without auth | |
| ``` | |
| --- | |
| ## Error Handling | |
| All `APIHelper` methods handle errors gracefully: | |
| ```javascript | |
| try { | |
| const data = await APIHelper.fetchAPI('/api/endpoint'); | |
| // Use data | |
| } catch (error) { | |
| // Error is already logged by APIHelper | |
| // Use fallback data | |
| const data = getDemoData(); | |
| } | |
| ``` | |
| --- | |
| ## Browser Compatibility | |
| - β Modern browsers (ES6+ modules) | |
| - β Chrome 61+ | |
| - β Firefox 60+ | |
| - β Safari 11+ | |
| - β Edge 16+ | |
| --- | |
| ## License | |
| Part of Crypto Monitor ULTIMATE project. | |