Now.js Framework Documentation
ApiService - High-level HTTP Service
ApiService - High-level HTTP Service
Documentation for ApiService, a High-level HTTP Service in the Now.js Framework
📋 Table of Contents
- Overview
- Installation and Import
- Getting Started
- Configuration
- HTTP Methods
- Caching System
- Authentication
- Request Deduplication
- Retry Mechanism
- Cache Management
- Advanced Features
- Usage Examples
- API Reference
- Best Practices
Overview
ApiService is a High-level HTTP Service built to handle complex HTTP requests with advanced features that enhance performance and security.
Key Features
- ✅ In-Memory Caching: Cache data in memory with expiration
- ✅ Request Deduplication: Prevent duplicate concurrent API calls
- ✅ Retry Mechanism: Automatic retry on network errors
- ✅ Authentication Management: Support Bearer, Basic, OAuth, Hybrid
- ✅ CSRF Protection: Automatic CSRF attack prevention
- ✅ JWT Auto-Refresh: Automatic token refresh before expiration
- ✅ Request Tracking: Track performance and errors
- ✅ Abort Controllers: Cancel pending requests
- ✅ Polling Support: Automatic endpoint polling
- ✅ Sequence Requests: Execute requests sequentially
When to Use ApiService
✅ Use ApiService when:
- You need caching for data that doesn't change frequently
- You need retry logic for network errors
- You need authentication management
- You need to prevent duplicate API calls
- You need request tracking and analytics
❌ Don't use ApiService when:
- You need simplicity (use
simpleFetchorhttpinstead) - Working with real-time data (shouldn't be cached)
- You don't need advanced features
Installation and Import
ApiService is loaded with the Now.js Framework and is ready to use immediately via the window object:
// No import needed - ready to use immediately
console.log(window.ApiService); // ApiService objectGetting Started
Basic Initialization
// Initialize with default config
await ApiService.init();
// Now you can make requests
const response = await ApiService.get('/api/users');
console.log(response.data);Initialization with Config
await ApiService.init({
baseURL: 'https://api.example.com',
debug: true,
cache: {
enabled: true,
expiry: {
get: 300000, // Cache GET requests for 5 minutes
post: 0, // Don't cache POST
put: 0,
delete: 0
}
},
security: {
csrfProtection: true,
bearerAuth: true,
bearerTokenKey: 'auth_token'
},
connection: {
timeout: 30000,
retryOnNetworkError: true,
maxNetworkRetries: 3
}
});Configuration
ApiService has multiple configuration sections that can be customized.
1. General Settings
{
baseURL: '', // Base URL for all requests
debug: false, // Enable debug logging
retryCount: 3, // Number of retries
retryDelay: 1000, // Delay between retries (ms)
deduplicate: true // Enable request deduplication
}2. Security Settings
{
security: {
// CSRF Protection
csrfProtection: true,
csrfHeaderName: 'X-CSRF-Token',
csrfCookieName: 'XSRF-TOKEN',
csrfTokenSelector: 'meta[name="csrf-token"]',
csrfIncludeSafeMethods: true,
// Bearer Authentication
bearerAuth: false,
bearerTokenKey: 'auth_token',
bearerPrefix: 'Bearer ',
// Basic Authentication
basicAuth: false,
basicUsername: '',
basicPassword: '',
// OAuth
oauth: false,
oauthTokenKey: 'oauth_token',
// JWT Auto-Refresh
jwtRefresh: false,
jwtRefreshEndpoint: 'api/auth/refresh',
jwtExpireKey: 'exp',
jwtRefreshBeforeExpirySec: 300,
// Authentication Strategy
authStrategy: 'hybrid', // 'hybrid', 'cookie', 'storage'
sendCredentials: true // Send cookies with requests
}
}3. Connection Settings
{
connection: {
timeout: 30000, // Request timeout (ms)
retryOnNetworkError: true, // Retry on network errors
maxNetworkRetries: 3, // Max retry attempts
backoffFactor: 1.5, // Backoff multiplier
retryStatusCodes: [408, 429, 500, 502, 503, 504],
exponentialBackoff: true // Use exponential backoff
}
}4. Cache Settings
{
cache: {
enabled: true,
storageType: 'memory', // 'memory', 'session', 'local'
maxSize: 100, // Max cache entries
expiry: {
default: 60000, // 1 minute
get: 60000, // Cache GET for 1 minute
post: 0, // Don't cache POST
put: 0, // Don't cache PUT
delete: 0 // Don't cache DELETE
},
keyGeneratorFn: null, // Custom cache key function
responsePredicate: null // Function to decide caching
}
}5. Tracking Settings
{
tracking: {
enabled: false,
errorTracking: true,
performanceTracking: false,
analyticsCallback: null, // Function to receive analytics
excludePaths: [] // Paths to exclude from tracking
}
}6. Logging Settings
{
logging: {
enabled: false,
logLevel: 'error', // 'debug', 'info', 'warn', 'error'
includeRequest: true,
includeResponse: true,
logToConsole: true,
customLogger: null // Custom logging function
}
}HTTP Methods
ApiService provides main HTTP methods for use.
GET Request
// Simple GET
const response = await ApiService.get('/api/users');
console.log(response.data);
// GET with parameters
const response = await ApiService.get('/api/users', {
page: 1,
limit: 10,
sort: 'name'
});
// GET with options
const response = await ApiService.get('/api/users', {}, {
cache: { enabled: false }, // Disable cache for this request
timeout: 5000 // Custom timeout
});POST Request
// Simple POST
const response = await ApiService.post('/api/users', {
name: 'John Doe',
email: 'john@example.com'
});
// POST with options
const response = await ApiService.post('/api/users', userData, {
headers: {
'X-Custom-Header': 'value'
}
});PUT Request
// Update resource
const response = await ApiService.put('/api/users/1', {
name: 'Jane Doe',
email: 'jane@example.com'
});DELETE Request
// Delete resource
const response = await ApiService.delete('/api/users/1');
// DELETE with options
const response = await ApiService.delete('/api/users/1', {
headers: {
'X-Reason': 'Account closed'
}
});Response Object
All methods return a response object with the same structure as HttpClient:
{
ok: boolean, // true if status 200-299
status: number, // HTTP status code
statusText: string, // HTTP status text
data: any, // Parsed response data
headers: object, // Response headers
url: string, // Request URL
fromCache: boolean, // true if from cache (GET only)
timestamp: number, // Timestamp (if available)
requestId: string|null // Request ID (if available)
}Caching System
ApiService has a powerful and flexible caching system.
Automatic Caching
await ApiService.init({
cache: {
enabled: true,
expiry: {
get: 300000 // Cache GET requests for 5 minutes
}
}
});
// First call - will call API
const response1 = await ApiService.get('/api/categories');
console.log(response1.fromCache); // false
// Second call within 5 minutes - will get from cache
const response2 = await ApiService.get('/api/categories');
console.log(response2.fromCache); // trueCache by Storage Type
Memory Cache (Default)
await ApiService.init({
cache: {
enabled: true,
storageType: 'memory' // Default - store in memory
}
});Advantages:
- ✅ Fastest
- ✅ No size limit (depends on memory)
Disadvantages:
- ❌ Lost on page refresh
Session Storage Cache
await ApiService.init({
cache: {
enabled: true,
storageType: 'session' // Store in sessionStorage
}
});Advantages:
- ✅ Persists throughout session
- ✅ Fast
Disadvantages:
- ❌ Lost when tab is closed
- ❌ Size limited (~5-10MB)
Local Storage Cache
await ApiService.init({
cache: {
enabled: true,
storageType: 'local' // Store in localStorage
}
});Advantages:
- ✅ Persists even after browser closes
- ✅ Shared between tabs
Disadvantages:
- ❌ Size limited (~5-10MB)
- ❌ Slower than memory
Custom Cache Key
await ApiService.init({
cache: {
enabled: true,
keyGeneratorFn: (url, params, method) => {
// Custom cache key logic
const userId = localStorage.getItem('user_id');
return `${userId}:${method}:${url}:${JSON.stringify(params)}`;
}
}
});Conditional Caching
await ApiService.init({
cache: {
enabled: true,
responsePredicate: (response) => {
// Cache only successful responses
return response.ok && response.status === 200;
}
}
});Cache Expiry by Method
await ApiService.init({
cache: {
enabled: true,
expiry: {
get: 600000, // Cache GET for 10 minutes
post: 0, // Don't cache POST
put: 0, // Don't cache PUT
delete: 0 // Don't cache DELETE
}
}
});Authentication
ApiService supports multiple authentication methods.
1. Bearer Token Authentication
Storage Strategy (Legacy)
await ApiService.init({
security: {
bearerAuth: true,
bearerTokenKey: 'auth_token',
authStrategy: 'storage' // Use localStorage
}
});
// Set token in localStorage
localStorage.setItem('auth_token', 'your-token-here');
// Requests will automatically include: Authorization: Bearer your-token
const response = await ApiService.get('/api/user/profile');Hybrid Strategy (Recommended)
await ApiService.init({
security: {
bearerAuth: true,
authStrategy: 'hybrid' // HttpOnly cookie + in-memory token
}
});
// Set access token (from login response)
ApiService.setAccessToken('short-lived-access-token');
// Requests will include: Authorization: Bearer short-lived-access-token
const response = await ApiService.get('/api/user/profile');
// Clear token on logout
ApiService.clearAccessToken();Cookie Strategy
await ApiService.init({
security: {
authStrategy: 'cookie', // Server handles auth via cookie
sendCredentials: true
}
});
// No Authorization header - server uses HttpOnly cookie
const response = await ApiService.get('/api/user/profile');2. Basic Authentication
await ApiService.init({
security: {
basicAuth: true,
basicUsername: 'admin',
basicPassword: 'secret123'
}
});
// Requests will include: Authorization: Basic YWRtaW46c2VjcmV0MTIz
const response = await ApiService.get('/api/admin/stats');3. JWT Auto-Refresh
await ApiService.init({
security: {
bearerAuth: true,
authStrategy: 'hybrid',
jwtRefresh: true,
jwtRefreshEndpoint: '/api/auth/refresh',
jwtExpireKey: 'exp',
jwtRefreshBeforeExpirySec: 300 // Refresh 5 minutes before expiry
}
});
// ApiService will automatically:
// 1. Parse JWT token to check expiry
// 2. Refresh token 5 minutes before it expires
// 3. Update access token in memory
// You don't need to do anything - just use ApiService normally
const response = await ApiService.get('/api/user/profile');4. CSRF Protection
await ApiService.init({
security: {
csrfProtection: true,
csrfHeaderName: 'X-CSRF-Token',
csrfCookieName: 'XSRF-TOKEN',
csrfTokenSelector: 'meta[name="csrf-token"]'
}
});
// CSRF token will be automatically:
// 1. Retrieved from meta tag or cookie
// 2. Attached to POST/PUT/DELETE requestsHTML:
<meta name="csrf-token" content="your-csrf-token">Request Deduplication
ApiService prevents duplicate concurrent API calls.
How It Works
await ApiService.init({
deduplicate: true // Default
});
// User clicks button multiple times rapidly
button.addEventListener('click', async () => {
const response = await ApiService.get('/api/data');
console.log(response.data);
});
// ApiService will:
// 1. Check if request is already pending
// 2. If yes, return the same promise
// 3. If no, make new request
// Result: Only 1 actual API call, all clicks share the same responseDisable Deduplication
await ApiService.init({
deduplicate: false // Allow duplicate requests
});Manual Cache Key
Deduplication uses cache key to identify requests:
// Same cache key = deduplicated
await ApiService.get('/api/users', { page: 1 });
await ApiService.get('/api/users', { page: 1 }); // Shares first request
// Different cache key = separate requests
await ApiService.get('/api/users', { page: 1 });
await ApiService.get('/api/users', { page: 2 }); // Makes second requestRetry Mechanism
ApiService automatically retries on errors.
Basic Retry
await ApiService.init({
retryCount: 3,
retryDelay: 1000,
connection: {
retryOnNetworkError: true,
maxNetworkRetries: 3
}
});
// ApiService will retry automatically on:
// 1. Network errors
// 2. Timeout errors
// 3. Server errors (500, 502, 503, 504)Exponential Backoff
await ApiService.init({
retryDelay: 1000,
connection: {
retryOnNetworkError: true,
maxNetworkRetries: 3,
backoffFactor: 1.5,
exponentialBackoff: true
}
});
// Retry delays:
// 1st retry: 1000ms
// 2nd retry: 1500ms (1000 * 1.5)
// 3rd retry: 2250ms (1500 * 1.5)Custom Retry Status Codes
await ApiService.init({
connection: {
retryStatusCodes: [408, 429, 500, 502, 503, 504],
maxNetworkRetries: 3
}
});
// Will retry on:
// 408 - Request Timeout
// 429 - Too Many Requests
// 500 - Internal Server Error
// 502 - Bad Gateway
// 503 - Service Unavailable
// 504 - Gateway TimeoutCache Management
ApiService provides methods for cache management.
Clear All Cache
// Clear all cache entries
ApiService.clearCache();Invalidate Specific Cache
// Invalidate by URL and params
ApiService.invalidateCache('/api/users', { page: 1 });
// Invalidate by URL (all params)
ApiService.invalidateCacheByUrl('/api/users');Automatic Cache Invalidation
// POST/PUT/DELETE automatically invalidate related cache
await ApiService.post('/api/users', userData);
// ^ This will invalidate cache for '/api/users'
await ApiService.put('/api/users/1', userData);
// ^ This will invalidate cache for '/api/users/1'
await ApiService.delete('/api/users/1');
// ^ This will invalidate cache for '/api/users/1'Check Cache Status
const response = await ApiService.get('/api/users');
if (response.fromCache) {
console.log('Data from cache');
} else {
console.log('Data from API');
}Advanced Features
1. Abort Requests
// Start request
const requestPromise = ApiService.get('/api/large-data');
// Abort after 5 seconds
setTimeout(() => {
ApiService.abort('/api/large-data');
}, 5000);
try {
const response = await requestPromise;
} catch (error) {
console.log('Request aborted');
}2. Polling
// Poll every 5 seconds
const stopPolling = ApiService.poll(
'/api/status',
{},
5000,
(response, error, count) => {
if (error) {
console.error('Poll error:', error);
return;
}
console.log('Poll #' + count, response.data);
},
{
maxPolls: 10, // Stop after 10 polls
condition: (response) => {
// Stop when status is 'completed'
return response.data.status === 'completed';
}
}
);
// Stop polling manually
// stopPolling();3. Sequential Requests
const requests = [
{ url: '/api/users', params: { page: 1 } },
{ url: '/api/posts', params: { page: 1 } },
{ url: '/api/comments', params: { page: 1 } }
];
const results = await ApiService.sequence(requests, (response) => {
// Process each response
return response.data;
});
console.log('All results:', results);4. Parallel Requests
const responses = await ApiService.all([
ApiService.get('/api/users'),
ApiService.get('/api/posts'),
ApiService.get('/api/comments')
]);
console.log('Users:', responses[0].data);
console.log('Posts:', responses[1].data);
console.log('Comments:', responses[2].data);5. Custom Logging
await ApiService.init({
logging: {
enabled: true,
logLevel: 'debug',
customLogger: (level, message, data) => {
// Send to external logging service
console.log(`[${level.toUpperCase()}] ${message}`, data);
// Example: Send to Sentry
if (level === 'error') {
// Sentry.captureException(data);
}
}
}
});6. Performance Tracking
await ApiService.init({
tracking: {
enabled: true,
performanceTracking: true,
analyticsCallback: (data) => {
if (data.type === 'performance') {
console.log(`${data.method} ${data.url} took ${data.duration}ms`);
// Send to analytics service
// analytics.track('api_request', data);
}
}
}
});Usage Examples
1. Simple API Call with Caching
await ApiService.init({
baseURL: 'https://api.example.com',
cache: {
enabled: true,
expiry: { get: 300000 } // 5 minutes
}
});
// First call
const categories = await ApiService.get('/api/categories');
console.log(categories.fromCache); // false
// Second call (within 5 minutes)
const categoriesCached = await ApiService.get('/api/categories');
console.log(categoriesCached.fromCache); // true2. Authentication with Bearer Token
await ApiService.init({
baseURL: 'https://api.example.com',
security: {
bearerAuth: true,
authStrategy: 'hybrid'
}
});
// Login
const loginResponse = await ApiService.post('/api/auth/login', {
email: 'user@example.com',
password: 'password123'
});
// Set access token
ApiService.setAccessToken(loginResponse.data.accessToken);
// Make authenticated requests
const profile = await ApiService.get('/api/user/profile');
console.log(profile.data);
// Logout
await ApiService.post('/api/auth/logout');
ApiService.clearAccessToken();3. Form Submission with CSRF
await ApiService.init({
security: {
csrfProtection: true
}
});
// CSRF token will be automatically attached
const response = await ApiService.post('/api/contact', {
name: 'John Doe',
email: 'john@example.com',
message: 'Hello!'
});4. Retry on Network Error
await ApiService.init({
connection: {
retryOnNetworkError: true,
maxNetworkRetries: 3,
backoffFactor: 1.5,
exponentialBackoff: true
}
});
// Will retry 3 times on network error
try {
const response = await ApiService.get('/api/data');
console.log(response.data);
} catch (error) {
console.error('Failed after 3 retries:', error);
}5. Polling for Status Updates
await ApiService.init({
baseURL: 'https://api.example.com'
});
// Start a long-running task
const task = await ApiService.post('/api/tasks', {
type: 'export',
format: 'pdf'
});
// Poll for status
const stopPolling = ApiService.poll(
`/api/tasks/${task.data.id}`,
{},
2000, // Poll every 2 seconds
(response, error, count) => {
if (error) {
console.error('Poll error:', error);
return;
}
const status = response.data.status;
console.log(`Poll #${count}: ${status}`);
if (status === 'completed') {
console.log('Task completed!', response.data.result);
}
},
{
maxPolls: 30, // Max 1 minute (30 * 2 seconds)
condition: (response) => {
// Stop when completed or failed
return ['completed', 'failed'].includes(response.data.status);
}
}
);6. Pagination with Caching
await ApiService.init({
baseURL: 'https://api.example.com',
cache: {
enabled: true,
expiry: { get: 60000 } // 1 minute
}
});
async function loadPage(page) {
const response = await ApiService.get('/api/products', {
page: page,
limit: 20
});
console.log(`Page ${page} (cached: ${response.fromCache})`);
return response.data;
}
// Load pages 1-3
const page1 = await loadPage(1); // API call
const page2 = await loadPage(2); // API call
const page3 = await loadPage(3); // API call
// Reload page 1 (within 1 minute)
const page1Again = await loadPage(1); // From cache7. File Upload
const fileInput = document.querySelector('#file');
const file = fileInput.files[0];
const formData = new FormData();
formData.append('file', file);
formData.append('title', 'My Document');
formData.append('category', 'reports');
const response = await ApiService.post('/api/upload', formData);
if (response.ok) {
console.log('Upload successful:', response.data.url);
}8. Search with Debouncing
let searchTimeout;
function handleSearch(query) {
// Clear previous timeout
clearTimeout(searchTimeout);
// Abort previous request
ApiService.abort('/api/search', { q: lastQuery });
// Set new timeout
searchTimeout = setTimeout(async () => {
const response = await ApiService.get('/api/search', {
q: query,
limit: 10
});
displayResults(response.data);
}, 300); // Wait 300ms after user stops typing
}
searchInput.addEventListener('input', (e) => {
handleSearch(e.target.value);
});9. Conditional Caching
await ApiService.init({
cache: {
enabled: true,
expiry: { get: 300000 },
responsePredicate: (response) => {
// Only cache successful responses with data
return response.ok &&
response.status === 200 &&
response.data &&
Object.keys(response.data).length > 0;
}
}
});
const response = await ApiService.get('/api/data');
// Will only be cached if response is successful and has data10. Error Handling
try {
const response = await ApiService.get('/api/users');
if (response.ok) {
console.log('Success:', response.data);
} else {
// Handle HTTP errors
switch (response.status) {
case 401:
// Redirect to login
window.location.href = '/login';
break;
case 403:
alert('Access denied');
break;
case 404:
console.error('Resource not found');
break;
case 500:
alert('Server error. Please try again later.');
break;
default:
console.error('Error:', response.statusText);
}
}
} catch (error) {
// Handle network errors
console.error('Network error:', error);
alert('Cannot connect to server. Please check your internet connection.');
}API Reference
Initialization
ApiService.init(options?: ConfigOptions): Promise<ApiService>HTTP Methods
get(url: string, params?: object, options?: RequestOptions): Promise<Response>
post(url: string, data: any, options?: RequestOptions): Promise<Response>
put(url: string, data: any, options?: RequestOptions): Promise<Response>
delete(url: string, options?: RequestOptions): Promise<Response>Authentication
setAccessToken(token: string): void
clearAccessToken(): voidCache Management
clearCache(): void
invalidateCache(url: string, params?: object): boolean
invalidateCacheByUrl(url: string): number
createCacheKey(url: string, params?: object, method?: string): stringRequest Control
abort(url: string, params?: object): booleanAdvanced Methods
all(requests: Promise[]): Promise<any[]>
poll(url: string, params?: object, interval?: number, callback: Function, options?: PollOptions): Function
sequence(requests: RequestConfig[], processor?: Function): Promise<any[]>Utility Methods
buildUrlWithParams(url: string, params?: object): stringBest Practices
1. ✅ Initialize Once
// ❌ Bad: Initialize every time
async function fetchData() {
await ApiService.init({ /* config */ });
return await ApiService.get('/api/data');
}
// ✅ Good: Initialize once
await ApiService.init({ /* config */ });
async function fetchData() {
return await ApiService.get('/api/data');
}2. ✅ Use Appropriate Cache Expiry
// ❌ Bad: Cache everything the same
await ApiService.init({
cache: {
enabled: true,
expiry: { get: 300000 } // 5 minutes for everything
}
});
// ✅ Good: Cache by data type
await ApiService.init({
cache: {
enabled: true,
expiry: {
get: 300000, // 5 minutes for normal data
post: 0, // Don't cache POST
put: 0,
delete: 0
}
}
});
// ✅ Better: Disable cache per request
const realtimeData = await ApiService.get('/api/live-stats', {}, {
cache: { enabled: false }
});3. ✅ Use Hybrid Auth Strategy
// ❌ Bad: Storage strategy (insecure)
await ApiService.init({
security: {
bearerAuth: true,
authStrategy: 'storage' // Token in localStorage
}
});
// ✅ Good: Hybrid strategy (more secure)
await ApiService.init({
security: {
bearerAuth: true,
authStrategy: 'hybrid', // Token in memory + HttpOnly cookie
jwtRefresh: true
}
});4. ✅ Handle Errors Properly
// ❌ Bad: Don't handle errors
const response = await ApiService.get('/api/data');
console.log(response.data); // May be undefined
// ✅ Good: Check response.ok
const response = await ApiService.get('/api/data');
if (response.ok) {
console.log(response.data);
} else {
console.error('Error:', response.statusText);
}
// ✅ Better: Use try-catch
try {
const response = await ApiService.get('/api/data');
if (response.ok) {
console.log(response.data);
}
} catch (error) {
console.error('Network error:', error);
}5. ✅ Enable CSRF Protection
// ✅ Good: Enable CSRF protection
await ApiService.init({
security: {
csrfProtection: true
}
});6. ✅ Use Retry Mechanism
// ✅ Good: Enable retry
await ApiService.init({
connection: {
retryOnNetworkError: true,
maxNetworkRetries: 3,
exponentialBackoff: true
}
});7. ✅ Cleanup Polling
// ❌ Bad: No cleanup
ApiService.poll('/api/status', {}, 5000, callback);
// ✅ Good: Store stop function
const stopPolling = ApiService.poll('/api/status', {}, 5000, callback);
// Cleanup when no longer needed
window.addEventListener('beforeunload', () => {
stopPolling();
});8. ✅ Abort Long Requests
// ✅ Good: Abort unwanted requests
const controller = new AbortController();
button.addEventListener('click', () => {
ApiService.get('/api/large-data', {}, {
signal: controller.signal
});
});
cancelButton.addEventListener('click', () => {
ApiService.abort('/api/large-data');
});9. ✅ Use Deduplication
// ✅ Good: Enable deduplication (default)
await ApiService.init({
deduplicate: true
});
// Prevent multiple clicks
button.addEventListener('click', async () => {
const response = await ApiService.get('/api/data');
// Multiple clicks will share the same request
});10. ✅ Clear Cache Appropriately
// ❌ Bad: Never clear cache
await ApiService.post('/api/users', userData);
// Old cache still exists
// ✅ Good: ApiService clears cache automatically
await ApiService.post('/api/users', userData);
// Cache for '/api/users' is automatically removed
// ✅ Better: Clear cache manually when needed
await ApiService.post('/api/settings', settings);
ApiService.invalidateCacheByUrl('/api'); // Clear all /api cacheSummary
When to Use ApiService
| Use Case | Use ApiService? |
|---|---|
| Data that doesn't change often (categories, config) | ✅ Yes - enable caching |
| Real-time data (stock prices, live stats) | ❌ No - use http or disable cache |
| Need authentication | ✅ Yes - has auth management |
| Need retry logic | ✅ Yes - has retry mechanism |
| Prevent duplicate clicks | ✅ Yes - has deduplication |
| Simple API call | ❌ Not needed - use simpleFetch or http |
| File download/upload | ✅ Can use - supports FormData |
| Polling | ✅ Yes - has built-in polling |
| Performance tracking | ✅ Yes - has tracking system |
Key Features
| Feature | Available | Note |
|---|---|---|
| Caching | ✅ | Memory, Session, Local storage |
| Deduplication | ✅ | Prevent duplicate requests |
| Retry | ✅ | With exponential backoff |
| Authentication | ✅ | Bearer, Basic, OAuth, Hybrid |
| CSRF Protection | ✅ | Automatic |
| JWT Refresh | ✅ | Auto-refresh before expiry |
| Polling | ✅ | With conditions |
| Abort | ✅ | Cancel pending requests |
| Tracking | ✅ | Performance & errors |
| Logging | ✅ | Multiple levels |