using DigitalData.TaskFlow.Application.Common.Exceptions; using DigitalData.TaskFlow.API.Contracts.Common; using DigitalData.TaskFlow.Domain.Common; using DigitalData.TaskFlow.Domain.Enums; using FluentValidation; using System.Text.Json; namespace DigitalData.TaskFlow.API.Middleware; /// /// Handles exceptions globally and returns ticket-compatible API envelopes. /// public sealed class ExceptionHandlingMiddleware(RequestDelegate next, ILogger logger) { private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web); /// /// Executes the middleware. /// /// HTTP context. public async Task InvokeAsync(HttpContext context) { try { await next(context); } catch (ApiException apiException) { logger.LogWarning(apiException, "API exception intercepted."); context.Response.StatusCode = apiException.StatusCode; context.Response.ContentType = "application/json"; var response = new MetaOnlyResponse { Meta = [ new MetaEntry { Code = (int)apiException.MetaCode, Message = apiException.Message } ] }; await context.Response.WriteAsync(JsonSerializer.Serialize(response, JsonOptions)); } catch (ValidationException validationException) { logger.LogWarning(validationException, "Validation failed."); context.Response.StatusCode = StatusCodes.Status400BadRequest; context.Response.ContentType = "application/json"; var message = validationException.Errors.FirstOrDefault()?.ErrorMessage ?? "Ungultiger Request"; var response = new MetaOnlyResponse { Meta = [ new MetaEntry { Code = (int)MetaCode.InvalidRequest, Message = message } ] }; await context.Response.WriteAsync(JsonSerializer.Serialize(response, JsonOptions)); } catch (NotSupportedException notSupportedException) { logger.LogWarning(notSupportedException, "Operation not supported yet."); context.Response.StatusCode = StatusCodes.Status500InternalServerError; context.Response.ContentType = "application/json"; var response = new MetaOnlyResponse { Meta = [ new MetaEntry { Code = (int)MetaCode.InternalError, Message = notSupportedException.Message } ] }; await context.Response.WriteAsync(JsonSerializer.Serialize(response, JsonOptions)); } catch (Exception exception) { logger.LogError(exception, "Unhandled exception."); context.Response.StatusCode = StatusCodes.Status500InternalServerError; context.Response.ContentType = "application/json"; var response = new MetaOnlyResponse { Meta = [ new MetaEntry { Code = (int)MetaCode.InternalError, Message = "Interner Fehler" } ] }; await context.Response.WriteAsync(JsonSerializer.Serialize(response, JsonOptions)); } } }