Skip to content

Commit 9ef6109

Browse files
committed
šŸ› Refactor error handling to improve user error message clarity and support ID logging
1 parent 93bfa17 commit 9ef6109

File tree

2 files changed

+24
-12
lines changed

2 files changed

+24
-12
lines changed

ā€Žpackages/service-library/src/servicelib/aiohttp/requests_validation.pyā€Ž

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def handle_validation_as_http_error(
5151
}
5252
for e in err.errors()
5353
]
54-
reason_msg = error_msg_template.format(
54+
user_error_message = error_msg_template.format(
5555
failed=", ".join(d["loc"] for d in details)
5656
)
5757

@@ -80,15 +80,14 @@ def handle_validation_as_http_error(
8080
error_str = json_dumps(
8181
{
8282
"error": {
83-
"msg": reason_msg,
83+
"msg": user_error_message,
8484
"resource": resource_name, # optional
8585
"details": details, # optional
8686
}
8787
}
8888
)
8989

9090
raise web.HTTPUnprocessableEntity( # 422
91-
reason=reason_msg,
9291
text=error_str,
9392
content_type=MIMETYPE_APPLICATION_JSON,
9493
) from err

ā€Žpackages/service-library/src/servicelib/aiohttp/rest_middlewares.pyā€Ž

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
from aiohttp.web_exceptions import HTTPError
1212
from aiohttp.web_request import Request
1313
from aiohttp.web_response import StreamResponse
14-
from common_library.error_codes import create_error_code
14+
from common_library.error_codes import ErrorCodeStr, create_error_code
1515
from common_library.json_serialization import json_dumps, json_loads
1616
from common_library.user_messages import user_message
17+
from models_library.basic_types import IDStr
1718
from models_library.rest_error import ErrorGet, ErrorItemType, LogMessageType
19+
from servicelib.rest_constants import RESPONSE_MODEL_POLICY
1820
from servicelib.status_codes_utils import is_5xx_server_error
1921

2022
from ..logging_errors import create_troubleshotting_log_kwargs
@@ -28,7 +30,6 @@
2830
safe_status_message,
2931
wrap_as_envelope,
3032
)
31-
from .rest_utils import EnvelopeFactory
3233
from .typing_extension import Handler, Middleware
3334
from .web_exceptions_extension import get_http_error_class_or_none
3435

@@ -49,7 +50,7 @@ def is_api_request(request: web.Request, api_version: str) -> bool:
4950

5051
def _create_error_context(
5152
request: web.BaseRequest, exception: Exception
52-
) -> tuple[str, dict[str, Any]]:
53+
) -> tuple[ErrorCodeStr, dict[str, Any]]:
5354
"""Create error code and context for logging purposes.
5455
5556
Returns:
@@ -66,7 +67,7 @@ def _create_error_context(
6667

6768
def _log_5xx_server_error(
6869
request: web.BaseRequest, exception: Exception, user_error_msg: str
69-
) -> None:
70+
) -> ErrorCodeStr:
7071
"""Log 5XX server errors with error code and context."""
7172
error_code, error_context = _create_error_context(request, exception)
7273

@@ -78,6 +79,7 @@ def _log_5xx_server_error(
7879
error_code=error_code,
7980
)
8081
)
82+
return error_code
8183

8284

8385
def _handle_unexpected_exception_as_500(
@@ -105,7 +107,10 @@ def _handle_unexpected_exception_as_500(
105107
def _handle_http_error(
106108
request: web.BaseRequest, exception: web.HTTPError
107109
) -> web.HTTPError:
108-
"""Handle standard HTTP errors by ensuring they're properly formatted."""
110+
"""Handle standard HTTP errors by ensuring they're properly formatted.
111+
112+
NOTE: this needs further refactoring to avoid code duplication
113+
"""
109114
assert request # nosec
110115
assert not exception.empty_body, "HTTPError should not have an empty body" # nosec
111116

@@ -118,6 +123,12 @@ def _handle_http_error(
118123
if not exception.text or not is_enveloped_from_text(exception.text):
119124
# NOTE: aiohttp.HTTPException creates `text = f"{self.status}: {self.reason}"`
120125
user_error_msg = exception.text or "Unexpected error"
126+
127+
error_code = None
128+
if is_5xx_server_error(exception.status):
129+
error_code = _log_5xx_server_error(request, exception, user_error_msg)
130+
error_code = IDStr(error_code)
131+
121132
error_model = ErrorGet(
122133
errors=[
123134
ErrorItemType.from_error(exception),
@@ -127,11 +138,13 @@ def _handle_http_error(
127138
LogMessageType(message=user_error_msg, level="ERROR"),
128139
],
129140
message=user_error_msg,
141+
support_id=error_code,
142+
)
143+
exception.text = json_dumps(
144+
wrap_as_envelope(
145+
error=error_model.model_dump(mode="json", **RESPONSE_MODEL_POLICY)
146+
)
130147
)
131-
exception.text = EnvelopeFactory(error=error_model).as_text()
132-
133-
if is_5xx_server_error(exception.status):
134-
_log_5xx_server_error(request, exception, user_error_msg)
135148

136149
return exception
137150

0 commit comments

Comments
Ā (0)