mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-23 12:31:09 -05:00
- Added migration to convert unique_together constraints to UniqueConstraint for RideModel. - Introduced RideFormMixin for handling entity suggestions in ride forms. - Created comprehensive code standards documentation outlining formatting, docstring requirements, complexity guidelines, and testing requirements. - Established error handling guidelines with a structured exception hierarchy and best practices for API and view error handling. - Documented view pattern guidelines, emphasizing the use of CBVs, FBVs, and ViewSets with examples. - Implemented a benchmarking script for query performance analysis and optimization. - Developed security documentation detailing measures, configurations, and a security checklist. - Compiled a database optimization guide covering indexing strategies, query optimization patterns, and computed fields.
5.3 KiB
5.3 KiB
Error Handling Guidelines
This document provides guidelines for handling errors consistently across the ThrillWiki backend.
Exception Hierarchy
ThrillWiki uses a structured exception hierarchy defined in apps/core/exceptions.py:
ThrillWikiException (base)
├── ValidationException (400)
├── NotFoundError (404)
├── PermissionDeniedError (403)
├── BusinessLogicError (400)
├── ServiceError (500)
├── ExternalServiceError (502)
├── CacheError (500)
│
├── Domain-specific exceptions:
│ ├── ParkError
│ │ ├── ParkNotFoundError
│ │ └── ParkOperationError
│ ├── RideError
│ │ ├── RideNotFoundError
│ │ └── RideOperationError
│ ├── LocationError
│ │ ├── InvalidCoordinatesError
│ │ └── GeolocationError
│ ├── ReviewError
│ │ ├── ReviewModerationError
│ │ └── DuplicateReviewError
│ └── AccountError
│ ├── InsufficientPermissionsError
│ └── EmailError
Using ErrorHandler
The ErrorHandler class in apps/core/utils/error_handling.py provides standardized error handling.
Template Views
from apps.core.utils.error_handling import ErrorHandler
from apps.core.exceptions import ServiceError
def my_view(request):
try:
result = SomeService.do_operation(...)
except ServiceError as e:
ErrorHandler.handle_view_error(
request,
e,
user_message="The operation failed. Please try again.",
log_message=f"Service operation failed for user {request.user.id}"
)
return redirect("some-fallback")
except ValidationError as e:
ErrorHandler.handle_view_error(
request,
e,
user_message="Invalid data provided",
level="warning"
)
return redirect("form-view")
API Views
from apps.core.utils.error_handling import ErrorHandler
from apps.core.exceptions import ServiceError
from rest_framework import status
class MyAPIView(APIView):
def post(self, request):
try:
result = SomeService.do_operation(...)
return ErrorHandler.api_success_response(
data=result,
message="Operation completed successfully"
)
except ServiceError as e:
return ErrorHandler.handle_api_error(
e,
user_message="Failed to complete operation",
status_code=status.HTTP_400_BAD_REQUEST
)
Best Practices
1. Always Catch Specific Exceptions
# Good
try:
park = ParkService.create_park(...)
except ParkOperationError as e:
# Handle park-specific error
pass
except ValidationException as e:
# Handle validation error
pass
# Bad
try:
park = ParkService.create_park(...)
except Exception as e:
# Too broad - loses error context
pass
2. Log with Appropriate Context
# Good
logger.error(
f"Park creation failed for user {user.id}: {error}",
exc_info=True,
extra={"user_id": user.id, "park_name": name}
)
# Bad
logger.error(f"Error: {error}")
3. Provide Clear User Messages
# Good - User-friendly and actionable
ErrorHandler.handle_view_error(
request,
error,
user_message="Unable to save your changes. Please check your input and try again."
)
# Bad - Technical details exposed to user
ErrorHandler.handle_view_error(
request,
error,
user_message=f"IntegrityError: UNIQUE constraint failed: parks_park.slug"
)
4. Use Appropriate HTTP Status Codes
| Error Type | Status Code | When to Use |
|---|---|---|
| ValidationException | 400 | Invalid user input |
| NotFoundError | 404 | Resource doesn't exist |
| PermissionDeniedError | 403 | User lacks permission |
| BusinessLogicError | 400 | Business rule violation |
| ServiceError | 500 | Internal service failure |
| ExternalServiceError | 502 | Third-party service failure |
5. Never Use Bare except: Clauses
# Never do this
try:
something()
except:
pass
# Always specify exception type
try:
something()
except SpecificException:
handle_error()
Error Response Format
API Error Response
{
"error": "User-friendly error message",
"detail": "Technical error details",
"error_code": "SPECIFIC_ERROR_CODE",
"details": {
"field": "Additional context"
}
}
API Success Response
{
"status": "success",
"message": "Operation completed successfully",
"data": {
// Response data
}
}
Creating Custom Exceptions
When creating domain-specific exceptions:
from apps.core.exceptions import BusinessLogicError
class MyDomainError(BusinessLogicError):
"""Raised when my domain operation fails."""
default_message = "My domain operation failed"
error_code = "MY_DOMAIN_ERROR"
status_code = 400
def __init__(self, context_value: str = None, **kwargs):
if context_value:
kwargs["details"] = {"context": context_value}
kwargs["message"] = f"Operation failed for: {context_value}"
super().__init__(**kwargs)