Fix error propagation: surface API validation messages in the UI
- UseJsonExceptionHandler now maps InvalidOperationException to 400 (was 500), so upstream business-rule rejections reach the browser as actionable messages. - CvMatcherController forwards Refit 4xx bodies from cv-matcher-api instead of swallowing them in a generic 502. - ErrorResponse.Score removed; CaptchaController puts the score in Detail. - Frontend extractApiError helper reads the server Error/error/title field for 4xx responses and falls back to a generic i18n string for 5xx / missing body. - All four failure handlers (CV upload, CV match, contact form, subscribe form) updated to use extractApiError with the correct rate-limit i18n key. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -70,7 +70,7 @@ namespace Api.Controllers
|
||||
{
|
||||
Error = "Captcha verification failed.",
|
||||
Code = "captcha_verification_failed",
|
||||
Score = verdict.Score
|
||||
Detail = verdict.Score.HasValue ? $"Score: {verdict.Score:0.00}" : null
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,16 @@ public sealed class CvMatcherController : ControllerBase
|
||||
_logger.LogWarning("CV upload proxy request was cancelled by the client.");
|
||||
return StatusCode(499, new ErrorResponse { Error = "Request cancelled.", Code = "request_cancelled" });
|
||||
}
|
||||
catch (Refit.ApiException apiEx) when ((int)apiEx.StatusCode < 500)
|
||||
{
|
||||
// Forward upstream 4xx errors (e.g. "File is too large", "Only PDF files supported")
|
||||
// so the browser can display the actionable message rather than a generic 502.
|
||||
var body = await apiEx.GetContentAsAsync<ErrorResponse>();
|
||||
_logger.LogWarning("Upstream cv-matcher-api returned {Status} during CV upload: {Error}",
|
||||
(int)apiEx.StatusCode, body?.Error);
|
||||
return StatusCode((int)apiEx.StatusCode,
|
||||
body ?? new ErrorResponse { Error = apiEx.Message, Code = "upstream_error" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "CV upload proxy request failed.");
|
||||
@@ -196,6 +206,16 @@ public sealed class CvMatcherController : ControllerBase
|
||||
_logger.LogWarning("Job match proxy request was cancelled by the client.");
|
||||
return StatusCode(499, new ErrorResponse { Error = "Request cancelled.", Code = "request_cancelled" });
|
||||
}
|
||||
catch (Refit.ApiException apiEx) when ((int)apiEx.StatusCode < 500)
|
||||
{
|
||||
// Forward upstream 4xx errors (e.g. "Could not extract enough job text",
|
||||
// "Invalid job URL") so the browser can display the actionable message.
|
||||
var body = await apiEx.GetContentAsAsync<ErrorResponse>();
|
||||
_logger.LogWarning("Upstream cv-matcher-api returned {Status} during job match: {Error}",
|
||||
(int)apiEx.StatusCode, body?.Error);
|
||||
return StatusCode((int)apiEx.StatusCode,
|
||||
body ?? new ErrorResponse { Error = apiEx.Message, Code = "upstream_error" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Job match proxy request failed.");
|
||||
|
||||
Reference in New Issue
Block a user