From 936ed416197c3c62738e2f85c7c8ba2b1ac2545d Mon Sep 17 00:00:00 2001 From: senke Date: Thu, 25 Dec 2025 22:42:07 +0100 Subject: [PATCH] [INT-API-003] Standardize error handling across all services --- ...EGRATION_PERFECTION_TODOLIST_TEMPLATE.json | 13 +-- .../src/features/auth/services/authService.ts | 88 +++++++------------ 2 files changed, 38 insertions(+), 63 deletions(-) diff --git a/VEZA_INTEGRATION_PERFECTION_TODOLIST_TEMPLATE.json b/VEZA_INTEGRATION_PERFECTION_TODOLIST_TEMPLATE.json index 85105c0db..710e84b23 100644 --- a/VEZA_INTEGRATION_PERFECTION_TODOLIST_TEMPLATE.json +++ b/VEZA_INTEGRATION_PERFECTION_TODOLIST_TEMPLATE.json @@ -500,7 +500,8 @@ "description": "Tous les services API doivent utiliser la même méthode de gestion d'erreurs.", "priority": "P1", "priority_rank": 14, - "status": "todo", + "status": "completed", + "completed_at": "2025-01-27T15:00:00Z", "estimated_hours": 2, "side": "frontend_only", "files_to_modify": [ @@ -1095,13 +1096,13 @@ }, "progress_tracking": { "total_tasks": 32, - "completed": 13, + "completed": 14, "in_progress": 0, - "todo": 19, + "todo": 18, "blocked": 0, - "completion_percentage": 41, - "last_updated": "2025-01-27T14:45:00Z", + "completion_percentage": 44, + "last_updated": "2025-01-27T15:00:00Z", "estimated_completion_date": null, - "estimated_hours_remaining": 29.5 + "estimated_hours_remaining": 27.5 } } diff --git a/apps/web/src/features/auth/services/authService.ts b/apps/web/src/features/auth/services/authService.ts index d86f973e1..ad6d8a537 100644 --- a/apps/web/src/features/auth/services/authService.ts +++ b/apps/web/src/features/auth/services/authService.ts @@ -1,5 +1,5 @@ import { apiClient } from '@/services/api/client'; -import axios, { AxiosError } from 'axios'; +import { handleApiServiceError } from '@/utils/serviceErrorHandler'; import type { LoginFormData, RegisterFormData, @@ -23,65 +23,25 @@ export interface AuthResponse { requires_2fa?: boolean; // BE-API-001: Flag indicating 2FA is required } -export interface ApiError { - message: string; - code?: string; - details?: Record; -} - -/** - * Gère les erreurs API de manière standardisée - */ -function handleApiError(error: unknown): never { - if (axios.isAxiosError(error)) { - const axiosError = error as AxiosError<{ - error?: string; - message?: string; - }>; - - if (axiosError.response) { - // Erreur de réponse du serveur - const errorMessage = - axiosError.response.data?.error || - axiosError.response.data?.message || - 'An error occurred'; - - const apiError: ApiError = { - message: errorMessage, - code: axiosError.response.status.toString(), - details: axiosError.response.data as Record, - }; - - throw apiError; - } else if (axiosError.request) { - // Requête envoyée mais pas de réponse - throw { - message: 'Network error: Unable to connect to server', - code: 'NETWORK_ERROR', - } as ApiError; - } - } - - // Erreur inconnue - throw { - message: - error instanceof Error ? error.message : 'An unexpected error occurred', - code: 'UNKNOWN_ERROR', - } as ApiError; -} - /** * Authentifie un utilisateur avec email et mot de passe * @param data - Données de connexion (email, password) * @returns Promise avec les tokens et les informations utilisateur * @throws ApiError en cas d'erreur */ +// INT-API-003: Standardized error handling using handleApiServiceError export async function login(data: LoginFormData): Promise { try { const response = await apiClient.post('/auth/login', data); return response.data; } catch (error) { - return handleApiError(error); + handleApiServiceError(error, { + context: 'auth', + customMessages: { + 401: 'Email ou mot de passe incorrect', + 403: 'Votre compte n\'est pas vérifié. Veuillez vérifier votre email.', + }, + }); } } @@ -91,6 +51,7 @@ export async function login(data: LoginFormData): Promise { * @returns Promise avec les tokens et les informations utilisateur * @throws ApiError en cas d'erreur */ +// INT-API-003: Standardized error handling using handleApiServiceError export async function register(data: RegisterFormData): Promise { try { const response = await apiClient.post('/auth/register', { @@ -101,7 +62,13 @@ export async function register(data: RegisterFormData): Promise { }); return response.data; } catch (error) { - return handleApiError(error); + handleApiServiceError(error, { + context: 'auth', + customMessages: { + 409: 'Cet email ou ce nom d\'utilisateur est déjà utilisé', + 400: 'Les données fournies sont invalides', + }, + }); } } @@ -109,11 +76,12 @@ export async function register(data: RegisterFormData): Promise { * Déconnecte l'utilisateur actuel * @throws ApiError en cas d'erreur */ +// INT-API-003: Standardized error handling using handleApiServiceError export async function logout(): Promise { try { await apiClient.post('/auth/logout'); } catch (error) { - return handleApiError(error); + handleApiServiceError(error, { context: 'auth' }); } } @@ -123,6 +91,7 @@ export async function logout(): Promise { * @returns Promise avec les nouveaux tokens et les informations utilisateur * @throws ApiError en cas d'erreur */ +// INT-API-003: Standardized error handling using handleApiServiceError export async function refreshToken( refreshToken: string, ): Promise { @@ -132,7 +101,7 @@ export async function refreshToken( }); return response.data; } catch (error) { - return handleApiError(error); + handleApiServiceError(error, { context: 'auth' }); } } @@ -141,13 +110,14 @@ export async function refreshToken( * @param data - Données contenant l'email * @throws ApiError en cas d'erreur */ +// INT-API-003: Standardized error handling using handleApiServiceError export async function requestPasswordReset( data: ForgotPasswordFormData, ): Promise { try { await apiClient.post('/auth/password/reset-request', data); } catch (error) { - return handleApiError(error); + handleApiServiceError(error, { context: 'auth' }); } } @@ -156,6 +126,7 @@ export async function requestPasswordReset( * @param data - Données contenant le token et le nouveau mot de passe * @throws ApiError en cas d'erreur */ +// INT-API-003: Standardized error handling using handleApiServiceError export async function resetPassword( data: ResetPasswordFormData, ): Promise { @@ -165,7 +136,7 @@ export async function resetPassword( password: data.password, }); } catch (error) { - return handleApiError(error); + handleApiServiceError(error, { context: 'auth' }); } } @@ -174,11 +145,12 @@ export async function resetPassword( * @param token - Token de vérification * @throws ApiError en cas d'erreur */ +// INT-API-003: Standardized error handling using handleApiServiceError export async function verifyEmail(token: string): Promise { try { await apiClient.get(`/auth/verify-email?token=${token}`); } catch (error) { - return handleApiError(error); + handleApiServiceError(error, { context: 'auth' }); } } @@ -187,11 +159,12 @@ export async function verifyEmail(token: string): Promise { * @param email - Email de l'utilisateur * @throws ApiError en cas d'erreur */ +// INT-API-003: Standardized error handling using handleApiServiceError export async function resendVerificationEmail(email: string): Promise { try { await apiClient.post('/auth/resend-verification', { email }); } catch (error) { - return handleApiError(error); + handleApiServiceError(error, { context: 'auth' }); } } @@ -201,6 +174,7 @@ export async function resendVerificationEmail(email: string): Promise { * @returns Promise avec true si disponible, false sinon * @throws ApiError en cas d'erreur */ +// INT-API-003: Standardized error handling using handleApiServiceError export async function checkUsernameAvailability( username: string, ): Promise { @@ -210,6 +184,6 @@ export async function checkUsernameAvailability( ); return response.data.available; } catch (error) { - return handleApiError(error); + handleApiServiceError(error, { context: 'auth' }); } }