books/docs/architecture/error-handling-strategy.md
Greg fa8acef423 Epic 1, Story 1.1: Project Initialization & Repository Setup
- Initialize Git repository with main branch
- Create comprehensive .gitignore for Node.js, React, and environment files
- Set up directory structure (frontend/, backend/, docs/)
- Create detailed README.md with project overview and setup instructions
- Add .env.example with all required environment variables
- Configure Prettier for consistent code formatting

All acceptance criteria met:
 Git repository initialized with appropriate .gitignore
 Directory structure matches Technical Assumptions
 README.md created with project overview and setup docs
 .env.example file with all required environment variables
 Prettier config files added for code formatting consistency

🤖 Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 15:12:30 +01:00

3.8 KiB

Error Handling Strategy

Error Flow

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

// Consistent error format across all API endpoints
interface ApiError {
  error: string;              // Human-readable error message
  details?: Record<string, any>; // 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

// 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

// 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);