From 17ebf5c2fe4478eaee03077f89b89859112c7ea2 Mon Sep 17 00:00:00 2001 From: javiermengual Date: Tue, 30 Dec 2025 13:20:08 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20con=20ayuda=20de=20ia=20,=20me=20ense?= =?UTF-8?q?=C3=B1a=20sobre=20como=20manejar=20errores=20y=20me=20ayuda=20c?= =?UTF-8?q?on=20una=20implementacion=20detallada=20siguiendo=20el=20estand?= =?UTF-8?q?ar=20RFC=207807?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DoliMiddlewareApi/Program.cs | 74 +++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/DoliMiddlewareApi/Program.cs b/DoliMiddlewareApi/Program.cs index e97329c..cf3c72d 100644 --- a/DoliMiddlewareApi/Program.cs +++ b/DoliMiddlewareApi/Program.cs @@ -35,25 +35,71 @@ app.UseExceptionHandler(errorApp => { var exceptionHandler = context.Features.Get(); var exception = exceptionHandler?.Error; + var logger = context.RequestServices.GetRequiredService>(); + var env = context.RequestServices.GetRequiredService(); - var (statusCode, message) = exception switch + // PASO 1: Clasificar el tipo de error + var (statusCode, title, detail, isExpectedError) = exception switch { - NotFoundException notFound => (StatusCodes.Status404NotFound, notFound.Message), - UnauthorizedException unauthorized => (StatusCodes.Status401Unauthorized, unauthorized.Message), - ForbiddenException forbidden => (StatusCodes.Status403Forbidden, forbidden.Message), - BadRequestException badRequest => (StatusCodes.Status400BadRequest, badRequest.Message), - ApiException apiEx => (StatusCodes.Status500InternalServerError, apiEx.Message), - _ => (StatusCodes.Status500InternalServerError, "An unexpected error occurred") + // ERRORES ESPERADOS (del negocio/cliente) - OK mostrar detalles + NotFoundException notFound => (StatusCodes.Status404NotFound, "Not Found", notFound.Message, true), + UnauthorizedException => (StatusCodes.Status401Unauthorized, "Unauthorized", "Invalid API credentials", true), + ForbiddenException forbidden => (StatusCodes.Status403Forbidden, "Forbidden", forbidden.Message, true), + BadRequestException badRequest => (StatusCodes.Status400BadRequest, "Bad Request", badRequest.Message, true), + + // ERROR DE API EXTERNA (Dolibarr) - Mostrar que es externo pero no detalles internos + ApiException apiEx => (StatusCodes.Status500InternalServerError, "External Service Error", + env.IsDevelopment() ? apiEx.Message : "The external service is temporarily unavailable", false), + + // ERRORES INESPERADOS (bugs del programador) + _ => (StatusCodes.Status500InternalServerError, "Internal Server Error", + env.IsDevelopment() + ? exception?.Message ?? "An unexpected error occurred" // DESARROLLO: muestra el error real + : "An unexpected error occurred. Please try again later.", // PRODUCCIÓN: mensaje genérico + false) }; - context.Response.StatusCode = statusCode; - context.Response.ContentType = "application/json"; - - await context.Response.WriteAsJsonAsync(new + // PASO 2: SIEMPRE loguear (crítico para debugging en producción) + if (isExpectedError) { - error = message, - statusCode - }); + // Errores esperados: log como Warning (no son bugs, son flujo normal) + logger.LogWarning(exception, + "Expected error: {ExceptionType} | Path: {Path} | Message: {Message}", + exception?.GetType().Name, context.Request.Path, exception?.Message); + } + else + { + // Errores inesperados: log como Error (son bugs que HAY QUE ARREGLAR) + logger.LogError(exception, + "UNHANDLED EXCEPTION: {ExceptionType} | Path: {Path} | Message: {Message} | StackTrace: {StackTrace}", + exception?.GetType().Name, context.Request.Path, exception?.Message, exception?.StackTrace); + } + + // PASO 3: Construir respuesta ProblemDetails (estándar RFC 7807) + context.Response.StatusCode = statusCode; + context.Response.ContentType = "application/problem+json"; + + var problemDetails = new Microsoft.AspNetCore.Mvc.ProblemDetails + { + Status = statusCode, + Title = title, + Detail = detail, + Instance = context.Request.Path + }; + + // PASO 4: EN DESARROLLO añadir info extra para debugging + if (env.IsDevelopment() && !isExpectedError) + { + problemDetails.Extensions["exceptionType"] = exception?.GetType().Name; + problemDetails.Extensions["stackTrace"] = exception?.StackTrace; + if (exception?.InnerException != null) + { + problemDetails.Extensions["innerException"] = exception.InnerException.Message; + problemDetails.Extensions["innerStackTrace"] = exception.InnerException.StackTrace; + } + } + + await context.Response.WriteAsJsonAsync(problemDetails); }); });