Updated API reference, error handling, and architecture docs to reflect the new persistent cart system with database storage. API Reference Updates (shop-api-reference.md): - Updated last modified date to 2025-11-23 - Updated cart response schemas to match CartResponse/CartItemResponse models - Added detailed schema tables for all cart endpoints - Documented all cart exceptions with examples (CART_ITEM_NOT_FOUND, INSUFFICIENT_INVENTORY_FOR_CART, etc.) - Added implementation notes about cart persistence and duplicate prevention - Updated all endpoint documentation with proper request/response schemas - Added CartOperationResponse and ClearCartResponse documentation Error Handling Updates (error-handling.md): - Added Shopping Cart Exceptions section with 6 cart-specific exceptions - Added Product Exceptions section - Added Inventory Exceptions section - Updated error response format to show structured WizamartException format - Added examples with error_code, message, status_code, and details fields - Documented the difference between structured and generic error formats Architecture Updates (overview.md): - Added cart_items table to database schema diagram - Documented session-based shopping cart in data model hierarchy 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
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)
}
)
Related Documentation
- Authentication - Authentication-related exceptions
- RBAC - Authorization and permission exceptions
- Rate Limiting - Rate limit error handling
- Testing Guide - Testing error scenarios