refactor(arch): revamp API-003 rule for exception handling pattern

Change API-003 from "must catch exceptions" to "must NOT raise HTTPException
directly". This aligns with the architecture where:
- Domain exceptions bubble up to global exception handler
- Endpoints should NOT catch and convert exceptions
- HTTPException should only be used by the global handler

Also adds:
- EXC-004: Domain exceptions must inherit from WizamartException
- EXC-005: Global exception handler must be registered

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-03 21:33:57 +01:00
parent dd0ba1ed5e
commit e116be1a2c

View File

@@ -21,7 +21,7 @@ principles:
description: "Use Pydantic models for request/response validation. Use SQLAlchemy models for database."
- name: "Proper Exception Handling"
description: "Services throw domain exceptions. Routes catch and convert to HTTPException."
description: "Services throw domain exceptions. Global handler converts to HTTP responses. Endpoints do NOT catch or raise HTTPException."
- name: "Multi-Tenancy"
description: "All queries must be scoped to vendor_id. No cross-vendor data access."
@@ -66,14 +66,19 @@ api_endpoint_rules:
- "db.query("
- id: "API-003"
name: "Endpoint must catch service exceptions and convert to HTTPException"
name: "Endpoint must NOT raise HTTPException directly"
severity: "error"
description: |
API endpoints must catch domain exceptions from services and convert them
to appropriate HTTPException with proper status codes.
API endpoints should NOT raise HTTPException directly. Instead, let domain
exceptions bubble up to the global exception handler which converts them
to appropriate HTTP responses. This ensures consistent error formatting
and centralized error handling.
pattern:
file_pattern: "app/api/v1/**/*.py"
check: "exception_handling"
anti_patterns:
- "raise HTTPException"
exceptions:
- "app/exceptions/handler.py" # Handler is allowed to use HTTPException
- id: "API-004"
name: "Endpoint must have proper authentication/authorization"
@@ -250,6 +255,32 @@ exception_rules:
- "logger.error"
- "exc_info=True"
- id: "EXC-004"
name: "Domain exceptions must inherit from WizamartException"
severity: "error"
description: |
All custom domain exceptions must inherit from WizamartException (or its
subclasses like ResourceNotFoundException, ValidationException, etc.).
This ensures the global exception handler catches and converts them properly.
pattern:
file_pattern: "app/exceptions/**/*.py"
required_base_class: "WizamartException"
example_good: |
class VendorNotFoundException(ResourceNotFoundException):
def __init__(self, vendor_code: str):
super().__init__(resource_type="Vendor", identifier=vendor_code)
- id: "EXC-005"
name: "Exception handler must be registered"
severity: "error"
description: |
The global exception handler must be set up in app initialization to
catch WizamartException and convert to HTTP responses.
pattern:
file_pattern: "app/main.py"
required_patterns:
- "setup_exception_handlers"
# ============================================================================
# NAMING CONVENTION RULES
# ============================================================================