feat: con ayuda de ia , me enseña sobre como manejar errores y me ayuda con una implementacion detallada siguiendo el estandar RFC 7807
This commit is contained in:
parent
220d02819c
commit
17ebf5c2fe
|
|
@ -35,25 +35,71 @@ app.UseExceptionHandler(errorApp =>
|
||||||
{
|
{
|
||||||
var exceptionHandler = context.Features.Get<IExceptionHandlerFeature>();
|
var exceptionHandler = context.Features.Get<IExceptionHandlerFeature>();
|
||||||
var exception = exceptionHandler?.Error;
|
var exception = exceptionHandler?.Error;
|
||||||
|
var logger = context.RequestServices.GetRequiredService<ILogger<Program>>();
|
||||||
|
var env = context.RequestServices.GetRequiredService<IWebHostEnvironment>();
|
||||||
|
|
||||||
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),
|
// ERRORES ESPERADOS (del negocio/cliente) - OK mostrar detalles
|
||||||
UnauthorizedException unauthorized => (StatusCodes.Status401Unauthorized, unauthorized.Message),
|
NotFoundException notFound => (StatusCodes.Status404NotFound, "Not Found", notFound.Message, true),
|
||||||
ForbiddenException forbidden => (StatusCodes.Status403Forbidden, forbidden.Message),
|
UnauthorizedException => (StatusCodes.Status401Unauthorized, "Unauthorized", "Invalid API credentials", true),
|
||||||
BadRequestException badRequest => (StatusCodes.Status400BadRequest, badRequest.Message),
|
ForbiddenException forbidden => (StatusCodes.Status403Forbidden, "Forbidden", forbidden.Message, true),
|
||||||
ApiException apiEx => (StatusCodes.Status500InternalServerError, apiEx.Message),
|
BadRequestException badRequest => (StatusCodes.Status400BadRequest, "Bad Request", badRequest.Message, true),
|
||||||
_ => (StatusCodes.Status500InternalServerError, "An unexpected error occurred")
|
|
||||||
|
// 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;
|
// PASO 2: SIEMPRE loguear (crítico para debugging en producción)
|
||||||
context.Response.ContentType = "application/json";
|
if (isExpectedError)
|
||||||
|
|
||||||
await context.Response.WriteAsJsonAsync(new
|
|
||||||
{
|
{
|
||||||
error = message,
|
// Errores esperados: log como Warning (no son bugs, son flujo normal)
|
||||||
statusCode
|
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue