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

8.0 KiB

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:

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:

{
  "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:

{
  "detail": "Error message",
  "status_code": 401
}

Rate Limit Error Response

Rate limit errors include additional information:

{
  "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

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

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:

# 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:

# 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:

# 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:

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

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

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:

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)
        }
    )