From 911592758ae7ba68cdc7130a2ff20624291eab65 Mon Sep 17 00:00:00 2001 From: m Date: Sun, 12 Jul 2026 13:53:39 +0200 Subject: [PATCH] handle https tatus --- mobile/api/client.ts | 12 +++++++++--- mobile/app/upload.tsx | 32 ++++++++++++++++++++++++++++++-- mobile/constants/api.ts | 2 +- mobile/hooks/useUpload.ts | 27 +++++++++++++++++++++++---- mobile/types/index.ts | 22 ++++++++++++++++++++++ 5 files changed, 85 insertions(+), 10 deletions(-) diff --git a/mobile/api/client.ts b/mobile/api/client.ts index 6c13e61..92402be 100644 --- a/mobile/api/client.ts +++ b/mobile/api/client.ts @@ -1,5 +1,5 @@ import { API_BASE_URL, ENDPOINTS } from '../constants/api'; -import { ApiError } from '../types'; +import { ApiError, HttpError } from '../types'; class ApiClient { private baseUrl: string; @@ -22,8 +22,14 @@ class ApiClient { }); if (!response.ok) { - const error: ApiError = await response.json(); - throw new Error(error.error?.message || 'Request failed'); + let message = 'Request failed'; + let code: string | undefined; + try { + const body: ApiError = await response.json(); + message = body.error?.message || message; + code = body.error?.code; + } catch {} + throw new HttpError(response.status, message, code); } return response.json(); diff --git a/mobile/app/upload.tsx b/mobile/app/upload.tsx index 296e407..2e78659 100644 --- a/mobile/app/upload.tsx +++ b/mobile/app/upload.tsx @@ -4,6 +4,24 @@ import * as ImagePicker from 'expo-image-picker'; import * as DocumentPicker from 'expo-document-picker'; import { useUpload, UploadFile } from '../hooks/useUpload'; import { UploadProgress } from '../components/UploadProgress'; +import { UploadError } from '../types'; + +function getUploadErrorMessage(err: UploadError): string { + switch (err.status) { + case 400: + return `${err.fileName} : format invalide (${err.message})`; + case 404: + return `${err.fileName} : endpoint introuvable`; + case 413: + return `${err.fileName} : fichier trop volumineux`; + case 500: + return `${err.fileName} : erreur serveur (${err.message})`; + case 0: + return `${err.fileName} : impossible de contacter le serveur`; + default: + return `${err.fileName} : erreur ${err.status} (${err.message})`; + } +} export function UploadScreen() { const [uploadStatus, setUploadStatus] = useState<'idle' | 'uploading' | 'processing' | 'success' | 'error'>('idle'); @@ -16,6 +34,7 @@ export function UploadScreen() { setUploadStatus('uploading'); setUploadedCount(0); setTotalCount(files.length); + setError(undefined); try { const response = await upload.mutateAsync(files); @@ -23,13 +42,22 @@ export function UploadScreen() { if (response.errors.length > 0) { setUploadStatus('error'); - setError(`${response.uploaded.length}/${totalCount} uploadés. Erreurs : ${response.errors.map((e) => e.name).join(', ')}`); + const messages = response.errors.map((e) => getUploadErrorMessage(e)); + setError( + `${response.uploaded.length}/${totalCount} uploadés.\n${messages.join('\n')}` + ); } else { setUploadStatus('success'); } } catch (err) { setUploadStatus('error'); - setError(err instanceof Error ? err.message : 'Upload failed'); + if (err instanceof UploadError) { + setError(getUploadErrorMessage(err)); + } else if (err instanceof Error) { + setError(err.message); + } else { + setError("Erreur inconnue lors de l'upload"); + } } }; diff --git a/mobile/constants/api.ts b/mobile/constants/api.ts index 31312aa..642f602 100644 --- a/mobile/constants/api.ts +++ b/mobile/constants/api.ts @@ -2,7 +2,7 @@ export const API_BASE_URL = process.env.EXPO_PUBLIC_API_BASE_URL || 'http://192. export const ENDPOINTS = { FILES: '/files', - FILE: '/file', + FILE: '/files', UPLOAD: '/files/upload', SEARCH: '/files/search', OCR_JOBS: '/ocr/jobs', diff --git a/mobile/hooks/useUpload.ts b/mobile/hooks/useUpload.ts index 88783d0..3d985db 100644 --- a/mobile/hooks/useUpload.ts +++ b/mobile/hooks/useUpload.ts @@ -2,7 +2,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { File, UploadType } from 'expo-file-system'; import { apiClient } from '../api/client'; import { API_BASE_URL, ENDPOINTS } from '../constants/api'; -import { OcrJob } from '../types'; +import { ApiError, OcrJob, UploadError } from '../types'; export type UploadFile = { uri: string; type: string; name: string }; export type UploadResult = { name: string; id: string }; @@ -21,23 +21,42 @@ export function useUpload() { fieldName: 'file', mimeType: file.type, }); + + if (result.status >= 400) { + let serverMessage = 'Erreur serveur'; + let serverCode: string | undefined; + try { + const body: ApiError = JSON.parse(result.body); + serverMessage = body.error?.message || serverMessage; + serverCode = body.error?.code; + } catch { + serverMessage = result.body || serverMessage; + } + throw new UploadError(file.name, result.status, serverMessage, serverCode); + } + return JSON.parse(result.body) as UploadResult; }) ); const uploaded: UploadResult[] = []; - const errors: { name: string; error: string }[] = []; + const errors: UploadError[] = []; results.forEach((r, i) => { if (r.status === 'fulfilled') { uploaded.push(r.value); } else { - errors.push({ name: files[i].name, error: r.reason?.message || 'Upload failed' }); + const reason = r.reason; + if (reason instanceof UploadError) { + errors.push(reason); + } else { + errors.push(new UploadError(files[i].name, 0, reason?.message || 'Upload failed')); + } } }); if (errors.length > 0 && uploaded.length === 0) { - throw new Error(errors.map((e) => `${e.name}: ${e.error}`).join('\n')); + throw errors[0]; } return { uploaded, errors }; diff --git a/mobile/types/index.ts b/mobile/types/index.ts index dfbfda4..4471a2b 100644 --- a/mobile/types/index.ts +++ b/mobile/types/index.ts @@ -38,3 +38,25 @@ export interface ApiError { message: string; }; } + +export class HttpError extends Error { + status: number; + code?: string; + + constructor(status: number, message: string, code?: string) { + super(message); + this.name = 'HttpError'; + this.status = status; + this.code = code; + } +} + +export class UploadError extends HttpError { + fileName: string; + + constructor(fileName: string, status: number, message: string, code?: string) { + super(status, message, code); + this.name = 'UploadError'; + this.fileName = fileName; + } +}