-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
The FluentMeet API currently has no centralized error handling strategy. Errors from different layers of the application (validation, authentication, business logic, unhandled exceptions) return inconsistent response shapes, making it difficult for frontend clients to parse and display error messages reliably. This inconsistency complicates debugging, increases client-side boilerplate, and provides a poor developer experience.
Proposed Solution
Implement a uniform error handling system by defining a standard error response schema, a hierarchy of custom application exceptions, and a set of global exception handlers registered with FastAPI. All API errors—whether from request validation, custom business logic, or unexpected failures—will be caught and transformed into a single, predictable JSON structure before being returned to the client.
Standard Error Response Format
{
"status": "error",
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": []
}User Stories
- As a frontend developer, I want every API error response to follow the same JSON structure, so I can build a single, reusable error-handling utility on the client side.
- As a backend developer, I want to throw descriptive custom exceptions from anywhere in the codebase and have them automatically formatted into a standard response, so I don't have to manually construct error responses in every endpoint.
- As a DevOps engineer, I want unhandled exceptions to be logged with full tracebacks on the server while returning only a generic error message to the client, so sensitive internal details are never leaked.
Acceptance Criteria
- A base
FluentMeetExceptionclass is defined inapp/core/exceptions.py, along with subclasses for common HTTP error scenarios (BadRequestException,UnauthorizedException,ForbiddenException,NotFoundException,ConflictException,InternalServerException). - A standard
ErrorResponsePydantic model is defined inapp/core/error_responses.pywith fields:status,code,message, anddetails. - Global exception handlers are implemented in
app/core/exception_handlers.pyto catch:FluentMeetException→ returns the exception's status code, error code, message, and details.RequestValidationError→ returns400 Bad Requestwith field-specific error details.HTTPException→ wraps FastAPI/Starlette HTTP exceptions in the standard format.- Unhandled
Exception→ returns500 Internal Server Errorwith a generic message and logs the traceback server-side.
- All exception handlers are registered in
app/main.pyvia aregister_exception_handlers(app)call. - The following HTTP status codes are used consistently:
400 Bad Request: Validation or business logic errors.401 Unauthorized: Authentication issues.403 Forbidden: Permission issues or soft-deleted user access.404 Not Found: Resource does not exist.409 Conflict: Duplicate resource (e.g., email already registered).500 Internal Server Error: Unexpected server failures.
- Existing endpoints (e.g., the health check) remain unaffected.
- Unit tests verify the correct status code and JSON shape for every handler.
Proposed Technical Details
app/core/exceptions.py: DefineFluentMeetException(Exception)withstatus_code,code,message, anddetailsattributes. Create subclasses that pre-setstatus_codeand a defaultcodestring (e.g.,NotFoundExceptiondefaults to404and"NOT_FOUND").app/core/error_responses.py: DefineErrorDetail(BaseModel)with optionalfieldand requiredmessage, andErrorResponse(BaseModel)withstatus="error",code,message, anddetails: list[ErrorDetail]. Include acreate_error_response()helper that returns aJSONResponse.app/core/exception_handlers.py: Implement four handler functions and aregister_exception_handlers(app)function that callsapp.add_exception_handler(...)for each.app/main.py: Import and callregister_exception_handlers(app)after theFastAPI()instance is created.tests/test_error_handling.py: UseTestClientwith temporary route injection to trigger each exception type and assert on the response status code and JSON body.
Tasks
- Create
app/core/exceptions.pywithFluentMeetExceptionand all subclasses. - Create
app/core/error_responses.pywithErrorResponse,ErrorDetail, and thecreate_error_response()helper. - Create
app/core/exception_handlers.pywith all four global handlers and theregister_exception_handlers()function. - Update
app/main.pyto import and callregister_exception_handlers(app). - Create
tests/test_error_handling.pywith tests for every exception handler. - Run the full test suite and verify all tests pass.
Open Questions/Considerations
- Should the
detailsfield in the error response include a request/correlation ID for tracing purposes? - Should rate-limiting errors (
429 Too Many Requests) be included in the custom exception hierarchy now or deferred to a later issue? - For validation errors, should the field path use dot notation (e.g.,
body.email) or just the field name (e.g.,email)?