frontend error management enhancement
This commit is contained in:
144
middleware/context_middleware.py
Normal file
144
middleware/context_middleware.py
Normal file
@@ -0,0 +1,144 @@
|
||||
# middleware/context_middleware.py
|
||||
"""
|
||||
Context Detection Middleware
|
||||
|
||||
Detects the request context type (API, Admin, Vendor Dashboard, Shop, or Fallback)
|
||||
and injects it into request.state for use by error handlers and other components.
|
||||
|
||||
This middleware runs independently and complements vendor_context_middleware.
|
||||
"""
|
||||
import logging
|
||||
from enum import Enum
|
||||
from fastapi import Request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RequestContext(str, Enum):
|
||||
"""Request context types for the application."""
|
||||
API = "api"
|
||||
ADMIN = "admin"
|
||||
VENDOR_DASHBOARD = "vendor"
|
||||
SHOP = "shop"
|
||||
FALLBACK = "fallback"
|
||||
|
||||
|
||||
class ContextManager:
|
||||
"""Manages context detection for multi-area application."""
|
||||
|
||||
@staticmethod
|
||||
def detect_context(request: Request) -> RequestContext:
|
||||
"""
|
||||
Detect the request context type.
|
||||
|
||||
Priority order:
|
||||
1. API → /api/* paths (highest priority, always JSON)
|
||||
2. Admin → /admin/* paths or admin.* subdomain
|
||||
3. Vendor Dashboard → /vendor/* paths (vendor management area)
|
||||
4. Shop → Vendor storefront (custom domain, subdomain, or shop paths)
|
||||
5. Fallback → Unknown/generic context
|
||||
|
||||
Args:
|
||||
request: FastAPI request object
|
||||
|
||||
Returns:
|
||||
RequestContext enum value
|
||||
"""
|
||||
path = request.url.path
|
||||
host = request.headers.get("host", "")
|
||||
|
||||
# Remove port from host if present
|
||||
if ":" in host:
|
||||
host = host.split(":")[0]
|
||||
|
||||
# 1. API context (highest priority)
|
||||
if path.startswith("/api/"):
|
||||
return RequestContext.API
|
||||
|
||||
# 2. Admin context
|
||||
if ContextManager._is_admin_context(request, host, path):
|
||||
return RequestContext.ADMIN
|
||||
|
||||
# 3. Vendor Dashboard context (vendor management area)
|
||||
if ContextManager._is_vendor_dashboard_context(path):
|
||||
return RequestContext.VENDOR_DASHBOARD
|
||||
|
||||
# 4. Shop context (vendor storefront)
|
||||
# Check if vendor context exists (set by vendor_context_middleware)
|
||||
if hasattr(request.state, 'vendor') and request.state.vendor:
|
||||
# If we have a vendor and it's not admin or vendor dashboard, it's shop
|
||||
return RequestContext.SHOP
|
||||
|
||||
# Also check shop-specific paths
|
||||
if path.startswith("/shop/"):
|
||||
return RequestContext.SHOP
|
||||
|
||||
# 5. Fallback for unknown contexts
|
||||
return RequestContext.FALLBACK
|
||||
|
||||
@staticmethod
|
||||
def _is_admin_context(request: Request, host: str, path: str) -> bool:
|
||||
"""Check if request is in admin context."""
|
||||
# Admin subdomain (admin.platform.com)
|
||||
if host.startswith("admin."):
|
||||
return True
|
||||
|
||||
# Admin path (/admin/*)
|
||||
if path.startswith("/admin"):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _is_vendor_dashboard_context(path: str) -> bool:
|
||||
"""Check if request is in vendor dashboard context."""
|
||||
# Vendor dashboard paths (/vendor/*)
|
||||
# Note: This is the vendor management area, not the shop
|
||||
if path.startswith("/vendor/"):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
async def context_middleware(request: Request, call_next):
|
||||
"""
|
||||
Middleware to detect and inject request context into request.state.
|
||||
|
||||
This should run AFTER vendor_context_middleware to have access to
|
||||
vendor information if available.
|
||||
|
||||
Injects:
|
||||
request.state.context_type: RequestContext enum value
|
||||
"""
|
||||
# Detect context
|
||||
context_type = ContextManager.detect_context(request)
|
||||
|
||||
# Inject into request state
|
||||
request.state.context_type = context_type
|
||||
|
||||
# Log context detection (debug level)
|
||||
logger.debug(
|
||||
f"[CONTEXT] Request context detected: {context_type.value}",
|
||||
extra={
|
||||
"path": request.url.path,
|
||||
"host": request.headers.get("host", ""),
|
||||
"context": context_type.value,
|
||||
}
|
||||
)
|
||||
|
||||
# Continue processing
|
||||
response = await call_next(request)
|
||||
return response
|
||||
|
||||
|
||||
def get_request_context(request: Request) -> RequestContext:
|
||||
"""
|
||||
Helper function to get current request context.
|
||||
|
||||
Args:
|
||||
request: FastAPI request object
|
||||
|
||||
Returns:
|
||||
RequestContext enum value (defaults to FALLBACK if not set)
|
||||
"""
|
||||
return getattr(request.state, "context_type", RequestContext.FALLBACK)
|
||||
Reference in New Issue
Block a user