Coverage for seedboxsync/front/apis/core/error.py: 100%
20 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-26 17:14 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-26 17:14 +0000
1#
2# Copyright (C) 2015-2026 Guillaume Kulakowski <guillaume@kulakowski.fr>
3#
4# For the full copyright and license information, please view the LICENSE
5# file that was distributed with this source code.
6#
7"""SeedboxSync api error module."""
9from datetime import datetime
10from typing import Any
11import uuid
12from flask import Response, jsonify
13from werkzeug.exceptions import BadRequest, HTTPException, NotFound, Unauthorized
14from seedboxsync.front.apis import api
15from seedboxsync.front.babel import gettext as _
18@api.errorhandler(BadRequest) # type: ignore[untyped-decorator]
19@api.errorhandler(NotFound) # type: ignore[untyped-decorator]
20@api.errorhandler(Unauthorized) # type: ignore[untyped-decorator]
21def api_errorhandler(error: BadRequest | NotFound | Unauthorized) -> tuple[dict[str, Any], int]:
22 """
23 Handle validation and not-found API errors.
25 Args:
26 error (BadRequest | NotFound | Unauthorized): HTTP exception to serialize.
28 Returns:
29 tuple[dict[str, Any], int]: Empty response body and HTTP status code.
30 """
31 status_code = error.code or 500
33 # Get Flask-RESTX error data or build it from the HTTP exception
34 data = getattr(
35 error,
36 "data",
37 {
38 "message": error.name,
39 "errors": error.description,
40 },
41 )
43 error.data = { # type: ignore[union-attr]
44 "type": "about:blank",
45 "success": False,
46 "status": status_code,
47 "title": data.get("message", ""),
48 **({"message": data["errors"]} if "errors" in data else {}),
49 "timestamp": datetime.now().astimezone().isoformat(),
50 "traceId": str(uuid.uuid4()),
51 }
53 return {}, status_code
56def error(exc: Exception) -> tuple[Response, int | None]:
57 """
58 Serialize an exception as a JSON API response.
60 Args:
61 exc (Exception): Exception raised while processing the request.
63 Returns:
64 tuple[Response, int | None]: JSON response and HTTP status code.
65 """
66 status_code = exc.code if isinstance(exc, HTTPException) else 500
67 title = exc.name if isinstance(exc, HTTPException) else _("Internal Server Error")
68 message = exc.description if isinstance(exc, HTTPException) else str(exc)
70 return (
71 jsonify(
72 {
73 "type": "about:blank",
74 "success": False,
75 "status": status_code,
76 "title": title,
77 "message": message,
78 "timestamp": datetime.now().astimezone().isoformat(),
79 "traceId": str(uuid.uuid4()),
80 }
81 ),
82 status_code,
83 )