- Implemented feedback state resolution for proforma list and update pages. - Created error view models for proforma and customer updates, including handling for various error types. - Added tests for error handling in proforma and customer list updates. - Introduced utility functions for building error view models and resolving feedback states. - Ensured translation support for error messages in Spanish. - Removed duplicate error alert components in customer module.
6.5 KiB
Tratamiento de errores HTTP en Frontend ERP
1. Objetivo
Cualquier error que cruce IDataSource desde el frontend ERP queda normalizado como ApiClientError.
Esto evita que los módulos consumidores dependan de AxiosError o inspeccionen response.data directamente.
2. Flujo
Axios
→ interceptor
→ IDataSource
→ normalizeAxiosError
→ ApiClientError
→ TanStack Query
→ controller
→ UI
3. Responsabilidades
setupInterceptors
→ auth, headers y refresh
normalizeAxiosError
→ normalización HTTP/transporte
ApiClientError
→ contrato transversal
TanStack Query
→ transporte del error al consumidor
Controller/Page Controller
→ decisión UX
UI
→ render
4. Clasificación
| Caso | kind |
|---|---|
| 400 | badRequest |
| 401 | unauthorized |
| 403 | forbidden |
| 404 | notFound |
| 409 | conflict |
| 422 | validation |
| 429 | rateLimited |
| 500-599 | server / unavailable |
| red | network |
| timeout | timeout |
| cancelación | cancelled |
| resto | unknown |
5. Problem Details
El frontend soporta Problem Details parciales y completos.
Campos reconocidos:
type
title
status
detail
instance
method
correlationId
code
source
errors
errors puede estar ausente, vacío o contener elementos parciales válidos.
6. Mensajes
ApiClientError.message
→ diagnóstico técnico estable
getUserErrorMessage
→ mensaje seguro genérico
controller/page controller
→ mensaje específico del caso de uso
ApiClientError.message no debe tratarse como texto UX por defecto.
7. Reglas para nuevos módulos
No comprobar AxiosError en controllers.
No leer error.response.data en UI.
No normalizar errores dentro de hooks.
No mostrar problem.detail automáticamente.
No crear clases de error HTTP por módulo.
No usar error.message como mensaje UX por defecto.
8. Ejemplo de consumo
if (isApiClientError(error) && error.kind === "notFound") {
// El controller decide el estado específico del recurso.
}
9. Niveles de error
La presentación distingue cuatro niveles:
1. Error de validación/formulario
2. Error inline o de mutation
3. Error bloqueante de página
4. Error inesperado de routing/render
Regla crítica:
PageErrorState
no conoce Axios
no conoce TanStack Query
no conoce React Router
no conoce ErrorBoundary
10. Decisiones no adoptadas
En esta fase no se introduce:
ErrorProvider global
toasts globales automáticos
framework de errores no HTTP
registro dinámico de errores
11. Estados visuales bloqueantes
Para errores que impiden renderizar una página completa, la UI debe usar un view model explícito y un componente dedicado de página.
ApiClientError
→ builder específico del caso de uso
→ PageErrorViewModel
→ Page Controller
→ PageErrorState
Reglas:
ErrorAlert
→ error inline y no bloqueante
PageErrorState
→ error que impide renderizar la página
componentes locales
→ errores embebidos en una subárea, como PDFViewer
NotFoundCard queda retirado. Su sustitución es:
404 real
→ PageErrorState variant="notFound"
success sin entidad válida
→ PageErrorState variant="unknown"
colección vacía
→ empty state
12. Listados paginados
En listados con placeholderData, el estado visual debe distinguir entre fallo bloqueante y error de refetch:
error inicial + sin data utilizable
→ PageErrorState
error durante refetch + data previa utilizable
→ mantener tabla
→ ErrorAlert inline
Reglas aplicadas en proformas, customers e issued-invoices:
cancelled
→ sin feedback visual
notFound en listados
→ no se interpreta como empty
→ se trata como error remoto anómalo
→ mapeado a unknown en esta fase
13. Detalle y edición de recursos
En pantallas de detalle o edición de una entidad:
ApiClientError.kind === notFound
→ ausencia real del recurso
→ PageErrorState específico de notFound
respuesta exitosa sin entidad válida
→ inconsistencia del contrato
→ variant unknown
cancelled
→ no renderiza pantalla bloqueante
La decisión no debe derivarse de !entity a secas. El page controller debe distinguir entre:
error HTTP real
inconsistencia de datos
cancelación
El patrón se aplica ya en:
proformas/detail
proformas/list
proformas/update
customers/list
customers/view
customers/update
issued-invoices/list
14. Queries HTTP
Para queries normales, el flujo estable es:
ApiClientError
→ builder específico del caso de uso
→ PageErrorState / ErrorAlert
Reglas:
error inicial sin datos
→ PageErrorState
error de refetch con datos previos
→ conservar contenido
→ ErrorAlert inline
mutation error
→ ErrorAlert o feedback local
cancelled
→ sin pantalla de error
En issued-invoices solo existe actualmente el listado principal y la descarga de PDF. No hay detalle, create ni update cableados en web; por eso la migración de esta fase cubre:
issued-invoices/list
→ PageErrorState para fallo bloqueante
→ ErrorAlert para refetch con datos previos
issued-invoices/download-pdf
→ feedback local mediante toast
→ no promueve el error a pantalla completa
15. Routing
Los errores del router no se interpretan como ApiClientError.
Flujo:
Route error
→ clasificador de app
→ RouteErrorPage
→ PageErrorState
Cobertura actual:
404
403
500
503
unknown
La clasificación vive en apps/web y usa errorElement en las ramas del router que montan shell autenticado, fullscreen y auth. Las rutas placeholder antiguas (dashboard, settings, catalog, quotes) pasan a reutilizar la misma base visual de PageErrorState.
16. Render inesperado
Los errores inesperados de render de React quedan separados de Query y Routing.
Flujo:
React render error
→ ErrorBoundary
→ RenderErrorFallback
→ PageErrorState
Reglas:
resetErrorBoundary()
→ retry real del boundary
Ir al inicio
→ acción explícita
no stack
no error.message
no problem.detail
17. Legacy
Estado final de piezas legacy relacionadas:
ErrorPage
→ eliminado y sustituido por RouteErrorPage / StaticRouteErrorPage
error-fallbacks
→ eliminado
ErrorOverlay
→ eliminado por ausencia de consumidores
NotFoundCard
→ eliminado globalmente
ErrorState
→ se mantiene como compatibilidad sobre PageErrorState
ErrorAlert
→ se mantiene para feedback inline no destructivo