Files
orion/docs/api/error-handling.md
Samir Boulahtit 3c7af0ccdf refactor: standardize markdown file naming to kebab-case convention
Renamed all documentation files to follow kebab-case naming standard:
- UPPERCASE files → lowercase (e.g., RBAC.md → rbac.md)
- snake_case files → kebab-case (e.g., icons_guide.md → icons-guide.md)
- SCREAMING_SNAKE_CASE → kebab-case (e.g., DATABASE_SETUP_GUIDE.md → database-setup-guide.md)

Files renamed (15 total):
API Documentation:
  - api/RBAC.md → api/rbac.md

Architecture:
  - architecture/API_CONSOLIDATION_PROPOSAL.md → api-consolidation-proposal.md
  - architecture/API_MIGRATION_STATUS.md → api-migration-status.md

Development:
  - development/AUTH_DEPENDENCIES_GUIDE.md → auth-dependencies-guide.md
  - development/CUSTOMER_AUTHENTICATION_IMPLEMENTATION.md → customer-authentication-implementation.md
  - development/CUSTOMER_AUTH_SUMMARY.md → customer-auth-summary.md
  - development/icons_guide.md → icons-guide.md

Database Seeder:
  - database-seeder/DATABASE_INIT_GUIDE.md → database-init-guide.md
  - database-seeder/DATABASE_QUICK_REFERENCE_GUIDE.md → database-quick-reference-guide.md
  - database-seeder/DATABASE_SEEDER_DOCUMENTATION.md → database-seeder-documentation.md
  - database-seeder/MAKEFILE_DATABASE_SEEDER.md → makefile-database-seeder.md

Error Rendering:
  - error-rendering/ERROR_RENDERING_DEVELOPER_DOCUMENTATION.md → error-rendering-developer-documentation.md
  - error-rendering/HTML_ERROR_RENDERING_FLOW_DIAGRAM.md → html-error-rendering-flow-diagram.md

Getting Started:
  - getting-started/DATABASE_QUICK_REFERENCE.md → database-quick-reference.md
  - getting-started/DATABASE_SETUP_GUIDE.md → database-setup-guide.md

Updates:
- Updated all references in mkdocs.yml
- Updated all cross-references in markdown files
- Verified mkdocs builds without warnings or errors

Standard: Use kebab-case (lowercase-with-hyphens) for all markdown files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 07:58:33 +01:00

293 lines
8.0 KiB
Markdown

# Error Handling
Comprehensive error handling system for the FastAPI multi-tenant e-commerce platform.
## Overview
The application uses a structured exception hierarchy with custom exception classes and centralized error handlers. All exceptions are logged, formatted consistently, and return appropriate HTTP status codes.
## Exception Hierarchy
### Base Exceptions
All custom exceptions inherit from base exception classes defined in `app.exceptions`:
```python
from app.exceptions import (
InvalidTokenException,
TokenExpiredException,
InvalidCredentialsException,
UserNotActiveException,
AdminRequiredException,
InsufficientPermissionsException,
RateLimitException
)
```
### Authentication Exceptions
| Exception | Status Code | Description |
|-----------|-------------|-------------|
| `InvalidTokenException` | 401 | JWT token is invalid, malformed, or missing required claims |
| `TokenExpiredException` | 401 | JWT token has expired |
| `InvalidCredentialsException` | 401 | Username/password authentication failed |
| `UserNotActiveException` | 403 | User account is inactive or disabled |
### Authorization Exceptions
| Exception | Status Code | Description |
|-----------|-------------|-------------|
| `AdminRequiredException` | 403 | Endpoint requires admin role |
| `InsufficientPermissionsException` | 403 | User lacks required permissions |
### Rate Limiting Exceptions
| Exception | Status Code | Description |
|-----------|-------------|-------------|
| `RateLimitException` | 429 | Too many requests, rate limit exceeded |
### Shopping Cart Exceptions
| Exception | Status Code | Description |
|-----------|-------------|-------------|
| `CartItemNotFoundException` | 404 | Cart item not found (product not in cart) |
| `InsufficientInventoryForCartException` | 400 | Product doesn't have enough inventory for cart operation |
| `InvalidCartQuantityException` | 422 | Cart quantity is invalid (e.g., less than min or greater than max) |
| `CartValidationException` | 422 | Cart data validation failed |
| `EmptyCartException` | 422 | Operation attempted on empty cart |
| `ProductNotAvailableForCartException` | 400 | Product is not available for adding to cart |
### Product Exceptions
| Exception | Status Code | Description |
|-----------|-------------|-------------|
| `ProductNotFoundException` | 404 | Product not found in vendor catalog |
| `ProductNotActiveException` | 400 | Product is inactive and cannot be purchased |
### Inventory Exceptions
| Exception | Status Code | Description |
|-----------|-------------|-------------|
| `InventoryNotFoundException` | 404 | Inventory record not found |
| `InsufficientInventoryException` | 400 | Not enough inventory for operation |
## Error Response Format
All custom exceptions (inheriting from `WizamartException`) return a structured JSON format:
```json
{
"error_code": "PRODUCT_NOT_FOUND",
"message": "Product with ID '123' not found in vendor 1 catalog",
"status_code": 404,
"details": {
"resource_type": "Product",
"identifier": "123",
"product_id": 123,
"vendor_id": 1
}
}
```
**Standard Fields:**
| Field | Type | Description |
|-------|------|-------------|
| `error_code` | string | Machine-readable error code (e.g., "CART_ITEM_NOT_FOUND") |
| `message` | string | Human-readable error message |
| `status_code` | integer | HTTP status code |
| `details` | object | Additional context-specific error details |
**Note:** Generic FastAPI/HTTP errors may still use the simpler format:
```json
{
"detail": "Error message",
"status_code": 401
}
```
### Rate Limit Error Response
Rate limit errors include additional information:
```json
{
"detail": "Rate limit exceeded",
"status_code": 429,
"retry_after": 3600,
"timestamp": "2024-11-16T13:00:00Z",
"path": "/api/v1/resource"
}
```
## Usage Examples
### Raising Exceptions in Code
```python
from app.exceptions import InvalidCredentialsException, AdminRequiredException
# Authentication failure
if not user:
raise InvalidCredentialsException("User not found")
# Authorization check
if user.role != "admin":
raise AdminRequiredException()
```
### Catching Exceptions in Routes
```python
from fastapi import HTTPException
from app.exceptions import InvalidTokenException
@app.post("/api/v1/auth/protected")
async def protected_endpoint(token: str):
try:
user_data = auth_manager.verify_token(token)
return {"user": user_data}
except InvalidTokenException as e:
# Exception will be caught by global handler
raise
except Exception as e:
# Unexpected errors
logger.error(f"Unexpected error: {e}")
raise HTTPException(status_code=500, detail="Internal server error")
```
## Context-Aware Error Handling
The error handling system is context-aware and provides different error formats based on the request context:
### API Requests (`/api/*`)
Returns JSON error responses suitable for API clients.
### Admin/Vendor Dashboard (`/admin/*`, `/vendor/*`)
Returns JSON errors or redirects to error pages based on accept headers.
### Shop Requests (`/shop/*`)
Returns themed error pages matching the vendor's shop design.
## Logging
All errors are automatically logged with the following information:
- Error type and message
- Request path and method
- User information (if authenticated)
- Stack trace (for unexpected errors)
- Timestamp
Example log output:
```
2024-11-16 13:00:00 [ERROR] middleware.auth: Token verification error: Token missing user identifier
2024-11-16 13:00:00 [ERROR] app.main: Request failed: POST /api/v1/auth/login - 401
```
## Best Practices
### 1. Use Specific Exceptions
Always use the most specific exception class available:
```python
# Good
raise InvalidCredentialsException("Invalid email or password")
# Avoid
raise HTTPException(status_code=401, detail="Invalid credentials")
```
### 2. Provide Meaningful Messages
Include context in error messages:
```python
# Good
raise InvalidTokenException("Token missing user identifier")
# Avoid
raise InvalidTokenException("Invalid token")
```
### 3. Don't Expose Sensitive Information
Never include sensitive data in error messages:
```python
# Good
raise InvalidCredentialsException("Invalid email or password")
# Avoid - reveals which field is wrong
raise InvalidCredentialsException(f"User {email} not found")
```
### 4. Log Before Raising
Log errors before raising them for debugging:
```python
try:
result = risky_operation()
except OperationFailed as e:
logger.error(f"Operation failed: {e}", exc_info=True)
raise InternalServerException("Operation failed")
```
## Testing Error Handling
### Unit Tests
```python
import pytest
from app.exceptions import InvalidTokenException
def test_invalid_token():
auth_manager = AuthManager()
with pytest.raises(InvalidTokenException) as exc_info:
auth_manager.verify_token("invalid-token")
assert "Could not validate credentials" in str(exc_info.value.message)
```
### Integration Tests
```python
def test_authentication_error_response(client):
response = client.post(
"/api/v1/auth/login",
json={"username": "wrong", "password": "wrong"}
)
assert response.status_code == 401
assert "detail" in response.json()
```
## Global Exception Handlers
The application registers global exception handlers in `main.py`:
```python
from fastapi import FastAPI
from app.exceptions import InvalidTokenException, RateLimitException
app = FastAPI()
@app.exception_handler(InvalidTokenException)
async def invalid_token_handler(request, exc):
return JSONResponse(
status_code=401,
content={
"detail": exc.message,
"status_code": 401,
"timestamp": datetime.now(timezone.utc).isoformat(),
"path": str(request.url.path)
}
)
```
## Related Documentation
- [Authentication](authentication.md) - Authentication-related exceptions
- [RBAC](rbac.md) - Authorization and permission exceptions
- [Rate Limiting](rate-limiting.md) - Rate limit error handling
- [Testing Guide](../testing/testing-guide.md) - Testing error scenarios