Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

---

## v4.3.2 - 11/12/2025
**REFATORAÇÃO**: Mudança no result pattern e na classe de erro
- Remove a redundância de codigo na criação de um Error
- Remove sobrecargas na criação de Result com Errors
- Simplifica as respostas de Errors
- Remove método redundante do middleware de validação do token

---

## v4.3.1 - 09/12/2025
**REFATORAÇÃO**: Remove o método de busca por id da entidade nos IAiModelService
Adiciona relacionamento entre entidade `ProductEmbeddings` e `Company` para uma melhor busca
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Companies>Samuel Zedec</Companies>
<Copyright>Copyright © $([System.DateTime]::Now.Year)</Copyright>
<Description>Sistema de gestão financeira para um lanchonete local</Description>
<Version>4.3.1</Version>
<Version>4.3.2</Version>
</PropertyGroup>

<!-- Repositório e Documentação -->
Expand Down
28 changes: 15 additions & 13 deletions src/Riber.Api/Common/Api/GlobalExceptionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,30 @@ namespace Riber.Api.Common.Api;
/// Trata exceções globais na aplicação registrando erros e formatando
/// uma resposta JSON padronizada para o cliente.
/// </summary>
public sealed class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger) : IExceptionHandler
public sealed class GlobalExceptionHandler(
ILogger<GlobalExceptionHandler> logger)
: IExceptionHandler
{
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
logger.LogError(exception, "Exception occurred: {ExceptionType} - {Message}",
logger.LogError(exception, "Exception occurred: {ExceptionType} - {Message}",
exception.GetType().Name, exception.Message);
(HttpStatusCode statusCode, string message, Dictionary<string, string[]> details) = MapExceptionToError(exception);
await httpContext.WriteErrorResponse(statusCode, message, details);

(HttpStatusCode statusCode, string message, Dictionary<string, string[]>? details) = MapExceptionToError(exception);
await httpContext.WriteErrorResponse(statusCode, message, details, cancellationToken);
return true;
}

private static (HttpStatusCode StatusCode, string Message, Dictionary<string, string[]> Details) MapExceptionToError(Exception exception)
private static (HttpStatusCode, string, Dictionary<string, string[]>?) MapExceptionToError(Exception exception)
=> exception switch
{
RequestTimeoutException timeoutEx => (timeoutEx.Code, timeoutEx.Message, []),
ValidationException validationEx => (HttpStatusCode.BadRequest, string.Empty, validationEx.Details),
Layer.ApplicationException applicationEx => (applicationEx.Code, applicationEx.Message, []),
DomainException domainEx => (HttpStatusCode.UnprocessableContent, domainEx.Message, []),
_ => (HttpStatusCode.InternalServerError, "Erro inesperado no servidor.", [])
RequestTimeoutException timeoutEx => (timeoutEx.Code, timeoutEx.Message, null),
ValidationException validationEx => (HttpStatusCode.BadRequest, "Dados Inválidos.", validationEx.Details),
Layer.ApplicationException applicationEx => (applicationEx.Code, applicationEx.Message, null),
DomainException domainEx => (HttpStatusCode.UnprocessableContent, domainEx.Message, null),
_ => (HttpStatusCode.InternalServerError, "Erro inesperado no servidor.", null)
};
}
11 changes: 5 additions & 6 deletions src/Riber.Api/Extensions/HttpContextExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@ public static async Task WriteErrorResponse(
this HttpContext context,
HttpStatusCode code,
string message,
Dictionary<string, string[]> details)
Dictionary<string, string[]>? details = null,
CancellationToken cancellationToken = default)
{
var response = details.Count == 0
? Result.Failure<object>(message, code)
: Result.Failure<object>(details, code);

var response = Result.Failure<object>(message, code, details);
var jsonResponse = JsonSerializer.Serialize(response, JsonOptions);

context.Response.StatusCode = (int)code;
context.Response.ContentType = "application/json";

await context.Response.WriteAsync(jsonResponse);
await context.Response.WriteAsync(jsonResponse, cancellationToken);
}
}
15 changes: 3 additions & 12 deletions src/Riber.Api/Middlewares/SecurityStampMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,20 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
(string? userId, string? tokenSecurityStamp) = ExtractUserClaims(context.User);
if (!Guid.TryParse(userId, out var userIdParse) || string.IsNullOrWhiteSpace(tokenSecurityStamp))
{
await RespondUnauthorized(context, "Token do usuário inválido ou mal formado.");
await context.WriteErrorResponse(HttpStatusCode.Unauthorized, "Token do usuário inválido ou mal formado.");
return;
}

var user = await userQueryService.FindByIdAsync(userIdParse);
if (user is null || user.SecurityStamp != tokenSecurityStamp)
{
await RespondUnauthorized(context, "Security stamp inválido ou usuário não encontrado.");
await context.WriteErrorResponse(HttpStatusCode.Unauthorized, "Security stamp inválido ou usuário não encontrado.");
return;
}

await next(context);
}

private static async Task RespondUnauthorized(HttpContext context, string message)
{
await context.WriteErrorResponse(
code: HttpStatusCode.Unauthorized,
message: message,
details: []
);
}

private static (string? userId, string? securityStamp) ExtractUserClaims(ClaimsPrincipal user)
{
var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
Expand Down
18 changes: 10 additions & 8 deletions src/Riber.Application/Common/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,19 @@ public static Result<T> Success<T>(
public static Result<EmptyResult> Failure(
string message,
HttpStatusCode statusCode = HttpStatusCode.BadRequest)
=> new(new EmptyResult(), false, new Error(message, statusCode), statusCode);
{
var error = new Error(message, statusCode, null);
return new Result<EmptyResult>(new EmptyResult(), false, error, statusCode);
}

public static Result<T> Failure<T>(
string message,
HttpStatusCode statusCode = HttpStatusCode.BadRequest)
=> new(default, false, new Error(message, statusCode), statusCode);

public static Result<T> Failure<T>(
Dictionary<string, string[]> details,
HttpStatusCode statusCode = HttpStatusCode.BadRequest)
=> new(default, false, new Error(details, statusCode), statusCode);
HttpStatusCode statusCode = HttpStatusCode.BadRequest,
Dictionary<string, string[]>? details = null)
{
var error = new Error(message, statusCode, details);
return new Result<T>(default, false, error, statusCode);
}

#endregion
}
Expand Down
10 changes: 2 additions & 8 deletions src/Riber.Domain/Abstractions/Error.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public sealed class Error

public string Type { get; init; } = string.Empty;
public string Message { get; init; } = string.Empty;
public Dictionary<string, string[]> Details { get; set; } = [];
public Dictionary<string, string[]>? Details { get; init; }

#endregion

Expand All @@ -21,17 +21,11 @@ public sealed class Error
[JsonConstructor]
public Error() { }

public Error(string message, HttpStatusCode statusCode)
public Error(string message, HttpStatusCode statusCode, Dictionary<string, string[]>? details)
{
Message = message;
Type = statusCode.ToString();
}

public Error(Dictionary<string, string[]> details, HttpStatusCode statusCode)
{
Message = "Dados Inválidos.";
Details = details;
Type = statusCode.ToString();
}

#endregion
Expand Down
Loading