/** * Service Error Handler * FE-API-013: Standardized error handling for API services * * Provides a consistent way to handle errors in API services with * proper error parsing, user-friendly messages, and context awareness. */ import { AxiosError } from 'axios'; import { parseApiError, formatErrorMessage, getValidationErrors } from './apiErrorHandler'; import { formatUserFriendlyError, isRetryableError } from './errorMessages'; import type { ApiError } from '@/types/api'; /** * Options for error handling */ export interface ErrorHandlerOptions { /** Context for context-specific error messages */ context?: 'auth' | 'upload' | 'playlist' | 'track' | 'conversation' | 'search'; /** Whether to include validation details in error messages */ includeDetails?: boolean; /** Custom error message overrides */ customMessages?: Record; /** Whether to throw the error or return it */ throwError?: boolean; } /** * Standard error handler for API services * @param error Unknown error from API call * @param options Error handling options * @returns Formatted error message or throws ApiError */ export function handleServiceError( error: unknown, options: ErrorHandlerOptions = {}, ): string { const { context, includeDetails = false, customMessages = {}, throwError = true, } = options; // Parse error to ApiError format const apiError = parseApiError(error); // Check for custom message override const status = typeof apiError.code === 'number' ? apiError.code : 0; if (status in customMessages) { const customMessage = customMessages[status]; if (throwError) { throw new Error(customMessage); } return customMessage; } // Format user-friendly message const userMessage = formatUserFriendlyError(apiError, context, includeDetails); if (throwError) { // Create a new Error with the user-friendly message // but preserve the ApiError structure for debugging const errorWithContext = new Error(userMessage) as Error & { apiError?: ApiError }; errorWithContext.apiError = apiError; throw errorWithContext; } return userMessage; } /** * Wrapper for API service functions with standardized error handling * @param apiCall Async function that makes an API call * @param options Error handling options * @returns Result of the API call * @throws Error with user-friendly message */ export async function withErrorHandling( apiCall: () => Promise, options: ErrorHandlerOptions = {}, ): Promise { try { return await apiCall(); } catch (error) { handleServiceError(error, options); // This should never be reached due to throwError default, but TypeScript needs it throw error; } } /** * Gets validation errors from an API error * @param error Unknown error from API call * @returns Record of field -> error message */ export function getServiceValidationErrors( error: unknown, ): Record { const apiError = parseApiError(error); return getValidationErrors(apiError); } /** * Checks if an error is a specific HTTP status * @param error Unknown error * @param status HTTP status code to check * @returns True if error matches the status */ export function isErrorStatus(error: unknown, status: number): boolean { const apiError = parseApiError(error); const errorStatus = typeof apiError.code === 'number' ? apiError.code : 0; return errorStatus === status; } /** * Checks if an error is a network error * @param error Unknown error * @returns True if it's a network error */ export function isNetworkError(error: unknown): boolean { if (error instanceof AxiosError) { return !error.response && !!error.request; } const apiError = parseApiError(error); const code = typeof apiError.code === 'number' ? apiError.code : 0; return code === 0 || code === 502 || code === 503; } /** * Gets a user-friendly error message for display in UI * @param error Unknown error * @param context Optional context for context-specific messages * @returns User-friendly error message */ export function getUserFriendlyMessage( error: unknown, context?: ErrorHandlerOptions['context'], ): string { const apiError = parseApiError(error); return formatUserFriendlyError(apiError, context); } /** * Error handler specifically for API service methods * Provides consistent error handling pattern for all service functions * * Usage: * ```typescript * export async function getSomething(id: string): Promise { * try { * const response = await apiClient.get(`/something/${id}`); * return response.data; * } catch (error) { * return handleApiServiceError(error, { * context: 'track', * customMessages: { * 404: 'Le morceau est introuvable', * }, * }); * } * } * ``` */ export function handleApiServiceError( error: unknown, options: ErrorHandlerOptions = {}, ): never { return handleServiceError(error, { ...options, throwError: true }) as never; }