namespace CareFix.Api.Infrastructure;
/// An error whose message is safe to show to the user.
public sealed class AppException(int status, string message, string? code = null) : Exception(message)
{
public int Status { get; } = status;
public string? Code { get; } = code;
public static AppException BadRequest(string m) => new(400, m);
public static AppException NotFound(string m) => new(404, m);
public static AppException Forbidden(string m) => new(403, m);
public static AppException Conflict(string m) => new(409, m);
}
public sealed class ErrorMiddleware(RequestDelegate next, ILogger log)
{
public async Task Invoke(HttpContext ctx)
{
try
{
await next(ctx);
}
catch (AppException ex)
{
if (ctx.Response.HasStarted) throw;
ctx.Response.StatusCode = ex.Status;
await ctx.Response.WriteAsJsonAsync(new { error = ex.Message, code = ex.Code });
}
catch (CareFix.Core.OpsException ex)
{
if (ctx.Response.HasStarted) throw;
ctx.Response.StatusCode = ex.Status;
await ctx.Response.WriteAsJsonAsync(new { error = ex.Message });
}
catch (Exception ex)
{
log.LogError(ex, "Unhandled error on {Path}", ctx.Request.Path);
if (ctx.Response.HasStarted) throw;
ctx.Response.StatusCode = 500;
await ctx.Response.WriteAsJsonAsync(new { error = "Unexpected server error. The details are in the server log." });
}
}
}