# Error Handling Strategy ## Error Flow ```mermaid sequenceDiagram participant User participant FE as Frontend participant API as Backend API participant DB as Database User->>FE: Submit invalid form FE->>FE: Validate input FE->>User: Show validation error (inline) User->>FE: Submit valid form FE->>API: POST request API->>API: Validate input (express-validator) alt Validation fails API-->>FE: 400 Bad Request {error, details} FE->>User: Display error message else Validation passes API->>DB: Query/mutation alt Database error DB-->>API: Error API->>API: Log error API-->>FE: 500 Server Error {error} FE->>User: Display generic error else Success DB-->>API: Data API-->>FE: 200/201 Success {data} FE->>User: Display success message end end ``` ## Error Response Format ```typescript // Consistent error format across all API endpoints interface ApiError { error: string; // Human-readable error message details?: Record; // Optional validation details timestamp?: string; // ISO timestamp requestId?: string; // For debugging (optional) } // Examples: // Validation error { "error": "Validation failed", "details": { "field": "deadlineDate", "message": "Deadline must be in the future" } } // Generic server error { "error": "Internal server error" } // Not found error { "error": "Book not found" } ``` ## Frontend Error Handling ```typescript // services/api.js - Global error handler async request(endpoint, options = {}) { try { const response = await fetch(`${API_BASE_URL}${endpoint}`, options); if (!response.ok) { const errorData = await response.json(); throw new ApiError(errorData.error, errorData.details, response.status); } return await response.json(); } catch (error) { if (error instanceof ApiError) { throw error; // Re-throw API errors } // Network errors or other fetch failures throw new ApiError('Network error. Please check your connection.'); } } // Custom error class class ApiError extends Error { constructor(message, details, statusCode) { super(message); this.name = 'ApiError'; this.details = details; this.statusCode = statusCode; } } // Component error handling try { await booksService.addBook(bookData); showSuccessMessage('Book added successfully!'); } catch (error) { if (error instanceof ApiError) { if (error.details) { // Show field-specific errors setFieldError(error.details.field, error.details.message); } else { // Show generic error showErrorMessage(error.message); } } else { showErrorMessage('An unexpected error occurred'); } } ``` ## Backend Error Handling ```typescript // middleware/errorHandler.js - Centralized error handler module.exports = (err, req, res, next) => { // Log error for debugging console.error('Error:', err); // Prisma errors if (err.code && err.code.startsWith('P')) { if (err.code === 'P2025') { return res.status(404).json({ error: 'Resource not found' }); } if (err.code === 'P2002') { return res.status(400).json({ error: 'Duplicate entry', details: { field: err.meta?.target?.[0] } }); } return res.status(500).json({ error: 'Database error' }); } // Validation errors (from express-validator) if (err.errors && Array.isArray(err.errors)) { return res.status(400).json({ error: 'Validation failed', details: err.errors, }); } // Default: Internal server error res.status(err.statusCode || 500).json({ error: err.message || 'Internal server error', }); }; // Usage in server.js app.use(errorHandler); ``` ---