Version 0.4.0
All checks were successful
Run linters on applied template / Python 3.13 lint and build (push) Successful in 1m40s

Changes:
- put ObservabilityMiddleware before ExceptionHandlerMiddleware to avoid repetative code
- add application startup and last metrics update metrics along with CPU usage metric and threads count
- move host and port to new uvicorn section at config along with new reload and forwarded_allow_ips
- add request_id and remove trace_id/span_id generation if tracing is disabled
- move logging logic from utils to observability
- pass trace_id/span_id in HEX form
This commit is contained in:
2026-01-03 11:01:43 +03:00
parent b8acb017fd
commit 53f14a8624
26 changed files with 901 additions and 730 deletions

View File

@@ -0,0 +1,7 @@
"""Authentication exceptions are located here."""
from {{project_slug}}.exceptions.base import {{ProjectName}}Error
class NotAuthorizedError({{ProjectName}}Error):
"""Exception to raise when user token is not set, but is required."""

View File

@@ -2,23 +2,37 @@
from typing import Callable, Type
from fastapi import HTTPException
from fastapi.responses import JSONResponse
from starlette.exceptions import HTTPException
class ExceptionMapper:
"""Maps exceptions to `JSONResponse` for FastAPI error handling."""
def __init__(self):
self._known_exceptions: dict[Type, Callable[[Exception], JSONResponse]] = {}
def register_simple(self, exception_type: Type, status_code: int, detail: str) -> None:
def register_simple(self, exception_type: Type, status_code: int, details: str) -> None:
"""Register simple response handler with setting status_code and details."""
self._known_exceptions[exception_type] = lambda _: JSONResponse(
{"code": status_code, "detail": detail}, status_code=status_code
{"error": f"{exception_type.__module__}.{exception_type.__qualname__}", "details": details},
status_code=status_code,
)
def register_func(self, exception_type: Type, func: Callable[[Exception], JSONResponse]) -> None:
"""Register complex response handler by passing function."""
self._known_exceptions[exception_type] = func
def get_status_code(self, exc: Exception) -> int:
"""Get status code of preparing response."""
if isinstance(exc, HTTPException):
return exc.status_code
if type(exc) in self._known_exceptions:
return self._known_exceptions[type(exc)](exc).status_code
return 500
def is_known(self, exc: Exception) -> bool:
return type(exc) in self._known_exceptions or isinstance(exc, HTTPException)
def apply(self, exc: Exception) -> JSONResponse: