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));
}
}
}