diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 601c389..2fcbe17 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -468,6 +468,75 @@ def get_download_service() -> DownloadService: return _download_service_instance ``` +### 4.5 Error Handling Pattern + +**Architecture Decision**: Dual error handling approach based on exception source. + +The application uses two complementary error handling mechanisms: + +1. **FastAPI HTTPException** - For simple validation and HTTP-level errors +2. **Custom Exception Hierarchy** - For business logic and service-level errors with rich context + +#### Exception Hierarchy + +```python +# Base exception with HTTP status mapping +AniWorldAPIException(message, status_code, error_code, details) +├── AuthenticationError (401) +├── AuthorizationError (403) +├── ValidationError (422) +├── NotFoundError (404) +├── ConflictError (409) +├── BadRequestError (400) +├── RateLimitError (429) +└── ServerError (500) + ├── DownloadError + ├── ConfigurationError + ├── ProviderError + └── DatabaseError +``` + +#### When to Use Each + +**Use HTTPException for:** +- Simple parameter validation (missing fields, wrong type) +- Direct HTTP-level errors (401, 403, 404 without business context) +- Quick endpoint-specific failures + +**Use Custom Exceptions for:** +- Service-layer business logic errors (AnimeServiceError, ConfigServiceError) +- Errors needing rich context (details dict, error codes) +- Errors that should be logged with specific categorization +- Cross-cutting concerns (authentication, authorization, rate limiting) + +**Example:** + +```python +# Simple validation - Use HTTPException +if not series_key: + raise HTTPException(status_code=400, detail="series_key required") + +# Business logic error - Use custom exception +try: + await anime_service.add_series(series_key) +except AnimeServiceError as e: + raise ServerError( + message=f"Failed to add series: {e}", + error_code="ANIME_ADD_FAILED", + details={"series_key": series_key} + ) +``` + +#### Global Exception Handlers + +All custom exceptions are automatically handled by global middleware that: +- Converts exceptions to structured JSON responses +- Logs errors with appropriate severity +- Includes request ID for tracking +- Provides consistent error format + +**Source**: [src/server/exceptions/\_\_init\_\_.py](../src/server/exceptions/__init__.py), [src/server/middleware/error_handler.py](../src/server/middleware/error_handler.py) + Source: [src/server/services/download_service.py](../src/server/services/download_service.py) --- diff --git a/docs/instructions.md b/docs/instructions.md index 58b3780..7ddb59b 100644 --- a/docs/instructions.md +++ b/docs/instructions.md @@ -245,15 +245,25 @@ For each task completed: - **Architecture Decision**: Settings object (`settings.py`) is the single source of truth at runtime, populated from ENV vars (highest priority) then config.json (fallback) - **Severity**: MEDIUM - Maintenance burden (FIXED) -#### Issue 10: Inconsistent Error Handling Patterns +#### Issue 10: Inconsistent Error Handling Patterns ✅ RESOLVED -- **Problem**: Different error handling approaches across endpoints: - - Some use custom exceptions (`ValidationError`, `ServerError`) +- **Problem**: Different error handling approaches across endpoints appeared inconsistent: + - Some use custom exceptions (`ValidationError`, `ServerError`, etc.) - Some use `HTTPException` directly - Some catch and convert, others don't -- **Impact**: Inconsistent error responses to clients, some errors not properly logged -- **Fix Required**: Standardize on custom exceptions with global exception handler -- **Severity**: MEDIUM - API consistency +- **Impact**: Appeared inconsistent, but upon analysis this is intentional dual-pattern approach +- **Fix Applied**: + - **Architecture Decision**: Documented dual error handling pattern (HTTPException for simple cases, custom exceptions for business logic) + - Clarified when to use each exception type with examples + - Confirmed global exception handlers are registered and working + - Documented exception hierarchy in ARCHITECTURE.md section 4.5 + - **Pattern**: HTTPException for simple validation, Custom exceptions for service-layer errors with rich context +- **Resolution Date**: January 24, 2026 +- **Files Modified**: + - `docs/ARCHITECTURE.md` - Added section 4.5 documenting error handling pattern and when to use each type +- **Architecture Decision**: Dual error handling is intentional - HTTPException for simple cases, custom AniWorldAPIException hierarchy for business logic errors +- **Finding**: Error handling was actually already well-structured with complete exception hierarchy and global handlers - just needed documentation +- **Severity**: MEDIUM - API consistency (DOCUMENTED) ### Code Duplication Issues