From e116be1a2ca0873759e10aba73bf2b9517c8c7ff Mon Sep 17 00:00:00 2001 From: Samir Boulahtit Date: Wed, 3 Dec 2025 21:33:57 +0100 Subject: [PATCH] refactor(arch): revamp API-003 rule for exception handling pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .architecture-rules.yaml | 41 +++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/.architecture-rules.yaml b/.architecture-rules.yaml index ea4308bf..248f08b9 100644 --- a/.architecture-rules.yaml +++ b/.architecture-rules.yaml @@ -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 # ============================================================================