Files
bakery-ia/frontend/src/api/services/index.ts
2025-07-22 17:12:37 +02:00

275 lines
6.9 KiB
TypeScript

// src/api/services/index.ts
/**
* Main API Services Index
* Central import point for all service modules
*/
// Import all service classes
export { AuthService, authService } from './authService';
export { DataService, dataService } from './dataService';
export { TrainingService, trainingService } from './trainingService';
export { ForecastingService, forecastingService } from './forecastingService';
export { NotificationService, notificationService } from './notificationService';
export { TenantService, tenantService } from './tenantService';
// Import base API client for custom implementations
export { apiClient } from '../base/apiClient';
// Re-export all types from the main types file
export * from '../types/api';
// Export additional service-specific types
export type {
DashboardStats,
UploadResponse,
DataValidation,
} from './dataService';
export type {
TrainingJobProgress,
ModelMetrics,
TrainingConfiguration,
} from './trainingService';
export type {
SingleForecastRequest,
BatchForecastRequest,
ForecastAlert,
QuickForecast,
BatchForecastStatus,
} from './forecastingService';
export type {
NotificationCreate,
NotificationResponse,
NotificationHistory,
NotificationTemplate,
NotificationStats,
BulkNotificationRequest,
BulkNotificationStatus,
} from './notificationService';
export type {
TenantCreate,
TenantUpdate,
TenantSettings,
TenantStats,
TenantUser,
InviteUser,
} from './tenantService';
// Create a unified API object for convenience
export const api = {
auth: authService,
data: dataService,
training: trainingService,
forecasting: forecastingService,
notifications: notificationService,
tenant: tenantService,
} as const;
// Type for the unified API object
export type ApiServices = typeof api;
// Service status type for monitoring
export interface ServiceStatus {
service: string;
status: 'healthy' | 'degraded' | 'down';
lastChecked: Date;
responseTime?: number;
error?: string;
}
// Health check utilities
export class ApiHealthChecker {
private static healthCheckEndpoints = {
auth: '/auth/health',
data: '/data/health',
training: '/training/health',
forecasting: '/forecasting/health',
notifications: '/notifications/health',
tenant: '/tenants/health',
};
/**
* Check health of all services
*/
static async checkAllServices(): Promise<Record<string, ServiceStatus>> {
const results: Record<string, ServiceStatus> = {};
for (const [serviceName, endpoint] of Object.entries(this.healthCheckEndpoints)) {
results[serviceName] = await this.checkService(serviceName, endpoint);
}
return results;
}
/**
* Check health of a specific service
*/
static async checkService(serviceName: string, endpoint: string): Promise<ServiceStatus> {
const startTime = Date.now();
try {
const response = await apiClient.get(endpoint, { timeout: 5000 });
const responseTime = Date.now() - startTime;
return {
service: serviceName,
status: response.status === 200 ? 'healthy' : 'degraded',
lastChecked: new Date(),
responseTime,
};
} catch (error: any) {
return {
service: serviceName,
status: 'down',
lastChecked: new Date(),
responseTime: Date.now() - startTime,
error: error.message || 'Unknown error',
};
}
}
/**
* Check if core services are available
*/
static async checkCoreServices(): Promise<boolean> {
const coreServices = ['auth', 'data', 'forecasting'];
const results = await this.checkAllServices();
return coreServices.every(
service => results[service]?.status === 'healthy'
);
}
}
// Error handling utilities
export class ApiErrorHandler {
/**
* Handle common API errors
*/
static handleError(error: any): never {
if (error.response) {
// Server responded with error status
const { status, data } = error.response;
switch (status) {
case 401:
throw new Error('Authentication required. Please log in again.');
case 403:
throw new Error('You do not have permission to perform this action.');
case 404:
throw new Error('The requested resource was not found.');
case 429:
throw new Error('Too many requests. Please try again later.');
case 500:
throw new Error('Server error. Please try again later.');
default:
throw new Error(data?.message || `Request failed with status ${status}`);
}
} else if (error.request) {
// Network error
throw new Error('Network error. Please check your connection.');
} else {
// Other error
throw new Error(error.message || 'An unexpected error occurred.');
}
}
/**
* Retry failed requests with exponential backoff
*/
static async retryRequest<T>(
requestFn: () => Promise<T>,
maxRetries: number = 3,
baseDelay: number = 1000
): Promise<T> {
let lastError: any;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await requestFn();
} catch (error: any) {
lastError = error;
// Don't retry on certain errors
if (error.response?.status === 401 || error.response?.status === 403) {
throw error;
}
// Don't retry on last attempt
if (attempt === maxRetries) {
break;
}
// Wait before retrying with exponential backoff
const delay = baseDelay * Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}
}
// Request cache utilities for performance optimization
export class ApiCache {
private static cache = new Map<string, { data: any; expires: number }>();
/**
* Get cached response
*/
static get<T>(key: string): T | null {
const cached = this.cache.get(key);
if (cached && cached.expires > Date.now()) {
return cached.data;
}
// Remove expired cache entry
if (cached) {
this.cache.delete(key);
}
return null;
}
/**
* Set cached response
*/
static set(key: string, data: any, ttlMs: number = 300000): void { // 5 minutes default
const expires = Date.now() + ttlMs;
this.cache.set(key, { data, expires });
}
/**
* Clear cache
*/
static clear(): void {
this.cache.clear();
}
/**
* Clear expired entries
*/
static cleanup(): void {
const now = Date.now();
for (const [key, value] of this.cache.entries()) {
if (value.expires <= now) {
this.cache.delete(key);
}
}
}
/**
* Generate cache key
*/
static generateKey(method: string, url: string, params?: any): string {
const paramStr = params ? JSON.stringify(params) : '';
return `${method}:${url}:${paramStr}`;
}
}
// Export default as the unified API object
export default api;