# ThrillWiki Frontend API Documentation Last updated: 2025-08-29 This document provides comprehensive documentation for all ThrillWiki API endpoints that the NextJS frontend should use. ## Authentication ThrillWiki uses JWT Bearer token authentication. After successful login or signup, you'll receive access and refresh tokens that must be included in subsequent API requests. ### Authentication Headers Include the access token in the Authorization header using Bearer format: ```typescript headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } ``` ### Token Management - **Access Token**: Short-lived token (1 hour) used for API requests - **Refresh Token**: Long-lived token (7 days) used to obtain new access tokens - **Token Rotation**: Refresh tokens are rotated on each refresh for enhanced security ## Base URL The frontend uses a Next.js proxy that routes API requests: - Frontend requests: `/v1/auth/login/`, `/v1/accounts/profile/`, etc. - Proxy adds `/api/` prefix: `/api/v1/auth/login/`, `/api/v1/accounts/profile/`, etc. - Backend receives: `/api/v1/auth/login/`, `/api/v1/accounts/profile/`, etc. **Important**: Frontend code should make requests to `/v1/...` endpoints, not `/api/v1/...` ## Moderation System API The moderation system provides comprehensive content moderation, user management, and administrative tools. All moderation endpoints require moderator-level permissions or above. ### Moderation Reports #### List Reports - **GET** `/api/v1/moderation/reports/` - **Permissions**: Moderators and above can view all reports, regular users can only view their own reports - **Query Parameters**: - `status`: Filter by report status (PENDING, UNDER_REVIEW, RESOLVED, DISMISSED) - `priority`: Filter by priority (LOW, MEDIUM, HIGH, URGENT) - `report_type`: Filter by report type (SPAM, HARASSMENT, INAPPROPRIATE_CONTENT, etc.) - `reported_by`: Filter by user ID who made the report - `assigned_moderator`: Filter by assigned moderator ID - `created_after`: Filter reports created after date (ISO format) - `created_before`: Filter reports created before date (ISO format) - `unassigned`: Boolean filter for unassigned reports - `overdue`: Boolean filter for overdue reports based on SLA - `search`: Search in reason and description fields - `ordering`: Order by fields (created_at, updated_at, priority, status) #### Create Report - **POST** `/api/v1/moderation/reports/` - **Permissions**: Any authenticated user - **Body**: CreateModerationReportData #### Get Report Details - **GET** `/api/v1/moderation/reports/{id}/` - **Permissions**: Moderators and above, or report creator #### Update Report - **PATCH** `/api/v1/moderation/reports/{id}/` - **Permissions**: Moderators and above - **Body**: Partial UpdateModerationReportData #### Assign Report - **POST** `/api/v1/moderation/reports/{id}/assign/` - **Permissions**: Moderators and above - **Body**: `{ "moderator_id": number }` #### Resolve Report - **POST** `/api/v1/moderation/reports/{id}/resolve/` - **Permissions**: Moderators and above - **Body**: `{ "resolution_action": string, "resolution_notes": string }` #### Report Statistics - **GET** `/api/v1/moderation/reports/stats/` - **Permissions**: Moderators and above - **Returns**: ModerationStatsData ### Moderation Queue #### List Queue Items - **GET** `/api/v1/moderation/queue/` - **Permissions**: Moderators and above - **Query Parameters**: - `status`: Filter by status (PENDING, IN_PROGRESS, COMPLETED, CANCELLED) - `priority`: Filter by priority (LOW, MEDIUM, HIGH, URGENT) - `item_type`: Filter by item type (CONTENT_REVIEW, USER_REVIEW, BULK_ACTION, etc.) - `assigned_to`: Filter by assigned moderator ID - `unassigned`: Boolean filter for unassigned items - `has_related_report`: Boolean filter for items with related reports - `search`: Search in title and description fields #### Get My Queue - **GET** `/api/v1/moderation/queue/my_queue/` - **Permissions**: Moderators and above - **Returns**: Queue items assigned to current user #### Assign Queue Item - **POST** `/api/v1/moderation/queue/{id}/assign/` - **Permissions**: Moderators and above - **Body**: `{ "moderator_id": number }` #### Unassign Queue Item - **POST** `/api/v1/moderation/queue/{id}/unassign/` - **Permissions**: Moderators and above #### Complete Queue Item - **POST** `/api/v1/moderation/queue/{id}/complete/` - **Permissions**: Moderators and above - **Body**: CompleteQueueItemData ### Moderation Actions #### List Actions - **GET** `/api/v1/moderation/actions/` - **Permissions**: Moderators and above - **Query Parameters**: - `action_type`: Filter by action type (WARNING, USER_SUSPENSION, USER_BAN, etc.) - `moderator`: Filter by moderator ID - `target_user`: Filter by target user ID - `is_active`: Boolean filter for active actions - `expired`: Boolean filter for expired actions - `expiring_soon`: Boolean filter for actions expiring within 24 hours - `has_related_report`: Boolean filter for actions with related reports #### Create Action - **POST** `/api/v1/moderation/actions/` - **Permissions**: Moderators and above (with role-based restrictions) - **Body**: CreateModerationActionData #### Get Active Actions - **GET** `/api/v1/moderation/actions/active/` - **Permissions**: Moderators and above #### Get Expired Actions - **GET** `/api/v1/moderation/actions/expired/` - **Permissions**: Moderators and above #### Deactivate Action - **POST** `/api/v1/moderation/actions/{id}/deactivate/` - **Permissions**: Moderators and above ### Bulk Operations #### List Bulk Operations - **GET** `/api/v1/moderation/bulk-operations/` - **Permissions**: Admins and superusers only - **Query Parameters**: - `status`: Filter by status (PENDING, RUNNING, COMPLETED, FAILED, CANCELLED) - `operation_type`: Filter by operation type - `priority`: Filter by priority - `created_by`: Filter by creator ID - `can_cancel`: Boolean filter for cancellable operations - `has_failures`: Boolean filter for operations with failures - `in_progress`: Boolean filter for operations in progress #### Create Bulk Operation - **POST** `/api/v1/moderation/bulk-operations/` - **Permissions**: Admins and superusers only - **Body**: CreateBulkOperationData #### Get Running Operations - **GET** `/api/v1/moderation/bulk-operations/running/` - **Permissions**: Admins and superusers only #### Cancel Operation - **POST** `/api/v1/moderation/bulk-operations/{id}/cancel/` - **Permissions**: Admins and superusers only #### Retry Operation - **POST** `/api/v1/moderation/bulk-operations/{id}/retry/` - **Permissions**: Admins and superusers only #### Get Operation Logs - **GET** `/api/v1/moderation/bulk-operations/{id}/logs/` - **Permissions**: Admins and superusers only ### User Moderation #### Get User Moderation Profile - **GET** `/api/v1/moderation/users/{id}/` - **Permissions**: Moderators and above - **Returns**: UserModerationProfileData #### Take Action Against User - **POST** `/api/v1/moderation/users/{id}/moderate/` - **Permissions**: Moderators and above - **Body**: CreateModerationActionData #### Search Users - **GET** `/api/v1/moderation/users/search/` - **Permissions**: Moderators and above - **Query Parameters**: - `query`: Search in username and email - `role`: Filter by user role - `has_restrictions`: Boolean filter for users with active restrictions #### User Moderation Statistics - **GET** `/api/v1/moderation/users/stats/` - **Permissions**: Moderators and above ## Parks API ### Parks Listing - **GET** `/api/v1/parks/` - **Query Parameters**: - `search`: Search in park names and descriptions - `country`: Filter by country code - `state`: Filter by state/province - `city`: Filter by city - `status`: Filter by operational status - `park_type`: Filter by park type - `has_rides`: Boolean filter for parks with rides - `ordering`: Order by fields (name, opened_date, ride_count, etc.) - `page`: Page number for pagination - `page_size`: Number of results per page ### Park Details - **GET** `/api/v1/parks/{slug}/` - **Returns**: Complete park information including rides, photos, and statistics ### Park Rides - **GET** `/api/v1/parks/{park_slug}/rides/` - **Query Parameters**: Similar filtering options as global rides endpoint ### Park Photos - **GET** `/api/v1/parks/{park_slug}/photos/` - **Query Parameters**: - `photo_type`: Filter by photo type (banner, card, gallery) - `ordering`: Order by upload date, likes, etc. ## Rides API ### Rides Listing - **GET** `/api/v1/rides/` - **Query Parameters**: - `search`: Search in ride names and descriptions - `park`: Filter by park slug - `manufacturer`: Filter by manufacturer slug - `ride_type`: Filter by ride type - `status`: Filter by operational status - `opened_after`: Filter rides opened after date - `opened_before`: Filter rides opened before date - `height_min`: Minimum height requirement - `height_max`: Maximum height requirement - `has_photos`: Boolean filter for rides with photos - `ordering`: Order by fields (name, opened_date, height, etc.) ### Ride Details - **GET** `/api/v1/rides/{park_slug}/{ride_slug}/` - **Returns**: Complete ride information including specifications, photos, and reviews ### Ride Photos - **GET** `/api/v1/rides/{park_slug}/{ride_slug}/photos/` ### Ride Reviews - **GET** `/api/v1/rides/{park_slug}/{ride_slug}/reviews/` - **POST** `/api/v1/rides/{park_slug}/{ride_slug}/reviews/` ## Manufacturers API ### Manufacturers Listing - **GET** `/api/v1/rides/manufacturers/` - **Query Parameters**: - `search`: Search in manufacturer names - `country`: Filter by country - `has_rides`: Boolean filter for manufacturers with rides - `ordering`: Order by name, ride_count, etc. ### Manufacturer Details - **GET** `/api/v1/rides/manufacturers/{slug}/` ### Manufacturer Rides - **GET** `/api/v1/rides/manufacturers/{slug}/rides/` ## Authentication API ### Login - **POST** `/api/v1/auth/login/` - **Body**: `{ "username": string, "password": string, "turnstile_token"?: string }` - **Returns**: JWT tokens and user data - **Response**: ```typescript { "access": string, "refresh": string, "user": { "id": number, "username": string, "email": string, "display_name": string, "is_active": boolean, "date_joined": string }, "message": string } ``` ### Signup - **POST** `/api/v1/auth/signup/` - **Body**: ```typescript { "username": string, "email": string, "password": string, "password_confirm": string, "display_name": string, // Required field "turnstile_token"?: string } ``` - **Returns**: JWT tokens and user data - **Response**: Same format as login response (access and refresh tokens) - **Note**: `display_name` is now required during registration. The system no longer uses separate first_name and last_name fields. ### Token Refresh - **POST** `/api/v1/auth/token/refresh/` - **Body**: `{ "refresh": string }` - **Returns**: New access token and optionally a new refresh token - **Response**: ```typescript { "access": string, "refresh"?: string // Only returned if refresh token rotation is enabled } ``` ### Social Authentication #### Google Login - **POST** `/api/v1/auth/social/google/` - **Body**: `{ "access_token": string }` - **Returns**: JWT tokens and user data (same format as regular login) - **Note**: The access_token should be obtained from Google OAuth flow #### Discord Login - **POST** `/api/v1/auth/social/discord/` - **Body**: `{ "access_token": string }` - **Returns**: JWT tokens and user data (same format as regular login) - **Note**: The access_token should be obtained from Discord OAuth flow #### Connect Social Account - **POST** `/api/v1/auth/social/{provider}/connect/` - **Permissions**: Authenticated users only - **Body**: `{ "access_token": string }` - **Returns**: `{ "success": boolean, "message": string }` - **Note**: Links a social account to an existing ThrillWiki account #### Disconnect Social Account - **POST** `/api/v1/auth/social/{provider}/disconnect/` - **Permissions**: Authenticated users only - **Returns**: `{ "success": boolean, "message": string }` #### Get Social Connections - **GET** `/api/v1/auth/social/connections/` - **Permissions**: Authenticated users only - **Returns**: ```typescript { "google": { "connected": boolean, "email"?: string }, "discord": { "connected": boolean, "username"?: string } } ``` ### Social Provider Management #### List Available Providers - **GET** `/api/v1/auth/social/providers/available/` - **Permissions**: Public access - **Returns**: List of available social providers for connection - **Response**: ```typescript { "available_providers": [ { "id": "google", "name": "Google", "auth_url": "https://example.com/accounts/google/login/", "connect_url": "https://example.com/api/v1/auth/social/connect/google/" } ], "count": number } ``` #### List Connected Providers - **GET** `/api/v1/auth/social/connected/` - **Permissions**: Authenticated users only - **Returns**: List of social providers connected to user's account - **Response**: ```typescript { "connected_providers": [ { "provider": "google", "provider_name": "Google", "uid": "user_id_on_provider", "date_joined": "2025-01-01T00:00:00Z", "can_disconnect": boolean, "disconnect_reason": string | null, "extra_data": object } ], "count": number, "has_password_auth": boolean, "can_disconnect_any": boolean } ``` #### Connect Social Provider - **POST** `/api/v1/auth/social/connect/{provider}/` - **Permissions**: Authenticated users only - **Parameters**: `provider` - Provider ID (e.g., 'google', 'discord') - **Returns**: Connection initiation response with auth URL - **Response**: ```typescript { "success": boolean, "message": string, "provider": string, "auth_url": string } ``` - **Error Responses**: - `400`: Provider already connected or invalid provider - `500`: Connection initiation failed #### Disconnect Social Provider - **DELETE** `/api/v1/auth/social/disconnect/{provider}/` - **Permissions**: Authenticated users only - **Parameters**: `provider` - Provider ID to disconnect - **Returns**: Disconnection result with safety information - **Response**: ```typescript { "success": boolean, "message": string, "provider": string, "remaining_providers": string[], "has_password_auth": boolean, "suggestions"?: string[] } ``` - **Error Responses**: - `400`: Cannot disconnect (safety validation failed) - `404`: Provider not connected - `500`: Disconnection failed #### Get Social Authentication Status - **GET** `/api/v1/auth/social/status/` - **Permissions**: Authenticated users only - **Returns**: Comprehensive social authentication status - **Response**: ```typescript { "user_id": number, "username": string, "email": string, "has_password_auth": boolean, "connected_providers": ConnectedProvider[], "total_auth_methods": number, "can_disconnect_any": boolean, "requires_password_setup": boolean } ``` ### Social Provider Safety Rules The social provider management system enforces strict safety rules to prevent users from locking themselves out: 1. **Disconnection Safety**: Users can only disconnect a social provider if they have: - Another social provider connected, OR - Email + password authentication set up 2. **Error Scenarios**: - **Only Provider + No Password**: "Cannot disconnect your only authentication method. Please set up a password or connect another social provider first." - **No Password Auth**: "Please set up email/password authentication before disconnecting this provider." 3. **Suggested Actions**: When disconnection is blocked, the API provides suggestions: - "Set up password authentication" - "Connect another social provider" ### Usage Examples #### Check Social Provider Status ```typescript const checkSocialStatus = async () => { try { const response = await fetch('/api/v1/auth/social/status/', { headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }); const data = await response.json(); if (data.requires_password_setup) { // Show password setup prompt showPasswordSetupModal(); } return data; } catch (error) { console.error('Failed to get social status:', error); } }; ``` #### Connect Social Provider ```typescript const connectProvider = async (provider: string) => { try { const response = await fetch(`/api/v1/auth/social/connect/${provider}/`, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }); const data = await response.json(); if (data.success) { // Redirect to provider auth URL window.location.href = data.auth_url; } } catch (error) { console.error('Failed to connect provider:', error); } }; ``` #### Disconnect Social Provider with Safety Check ```typescript const disconnectProvider = async (provider: string) => { try { const response = await fetch(`/api/v1/auth/social/disconnect/${provider}/`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }); const data = await response.json(); if (!response.ok) { if (response.status === 400) { // Show safety warning with suggestions showSafetyWarning(data.error, data.suggestions); } return; } // Success - update UI toast.success(data.message); refreshConnectedProviders(); } catch (error) { console.error('Failed to disconnect provider:', error); } }; ``` #### React Component Example ```typescript import { useState, useEffect } from 'react'; interface SocialProvider { provider: string; provider_name: string; can_disconnect: boolean; disconnect_reason?: string; } const SocialProviderManager: React.FC = () => { const [connectedProviders, setConnectedProviders] = useState([]); const [hasPasswordAuth, setHasPasswordAuth] = useState(false); useEffect(() => { loadConnectedProviders(); }, []); const loadConnectedProviders = async () => { const response = await fetch('/api/v1/auth/social/connected/', { headers: { 'Authorization': `Bearer ${accessToken}` } }); const data = await response.json(); setConnectedProviders(data.connected_providers); setHasPasswordAuth(data.has_password_auth); }; const handleDisconnect = async (provider: string) => { const response = await fetch(`/api/v1/auth/social/disconnect/${provider}/`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${accessToken}` } }); if (!response.ok) { const error = await response.json(); alert(error.error + '\n\nSuggestions:\n' + error.suggestions?.join('\n')); return; } loadConnectedProviders(); // Refresh list }; return (

Connected Social Accounts

{!hasPasswordAuth && connectedProviders.length === 1 && (

⚠️ Set up a password to safely manage your social connections

)} {connectedProviders.map((provider) => (
{provider.provider_name}
))}
); }; ``` ### Logout - **POST** `/api/v1/auth/logout/` - **Returns**: `{ "message": string }` ### Current User - **GET** `/api/v1/auth/user/` - **Returns**: Current user profile data - **Response**: ```typescript { "id": number, "username": string, "email": string, "display_name": string, "is_active": boolean, "date_joined": string } ``` ### Password Reset - **POST** `/api/v1/auth/password/reset/` - **Body**: `{ "email": string }` ### Password Change - **POST** `/api/v1/auth/password/change/` - **Body**: `{ "old_password": string, "new_password": string }` ## User Account Management API ### User Profile - **GET** `/api/v1/accounts/profile/` - **Permissions**: Authenticated users only - **Returns**: Complete user profile including account details, preferences, and statistics ### Update Account - **PATCH** `/api/v1/accounts/profile/account/` - **Permissions**: Authenticated users only - **Body**: `{ "display_name"?: string, "email"?: string }` ### Update Profile - **PATCH** `/api/v1/accounts/profile/update/` - **Permissions**: Authenticated users only - **Body**: `{ "display_name"?: string, "pronouns"?: string, "bio"?: string, "twitter"?: string, "instagram"?: string, "youtube"?: string, "discord"?: string }` ### Avatar Upload - **POST** `/api/v1/accounts/profile/avatar/upload/` - **Permissions**: Authenticated users only - **Content-Type**: `multipart/form-data` - **Body**: FormData with `avatar` field containing image file (JPEG, PNG, WebP) - **Returns**: ```typescript { "success": boolean, "message": string, "avatar_url": string, "avatar_variants": { "thumbnail": string, // 64x64 "avatar": string, // 200x200 "large": string // 400x400 } } ``` **⚠️ CRITICAL AUTHENTICATION REQUIREMENT**: - This endpoint requires authentication via JWT token in Authorization header - **Common Issue**: "Authentication credentials were not provided" (401 error) - **Root Cause**: User not logged in or JWT token not being sent - **Debug Steps**: See `docs/avatar-upload-debugging.md` for comprehensive troubleshooting guide **Usage Example**: ```typescript // Ensure user is logged in first const { user } = useAuth(); if (!user) { // Redirect to login return; } // Upload avatar const file = event.target.files[0]; const response = await accountApi.uploadAvatar(file); ``` **Test Credentials** (for debugging): - Username: `testuser` - Password: `testpass123` - Email: `test@example.com` **Recent Fix (2025-08-29)**: - Fixed file corruption issue where PNG headers were being corrupted during upload - Frontend now passes FormData directly instead of extracting and re-wrapping files - Backend includes corruption detection and repair mechanism - See `docs/avatar-upload-debugging.md` for complete technical details ### Avatar Delete - **DELETE** `/api/v1/accounts/profile/avatar/delete/` - **Permissions**: Authenticated users only - **Returns**: `{ "success": boolean, "message": string, "avatar_url": string }` ### User Preferences - **GET** `/api/v1/accounts/preferences/` - **PATCH** `/api/v1/accounts/preferences/update/` - **Permissions**: Authenticated users only ### Notification Settings - **GET** `/api/v1/accounts/settings/notifications/` - **PATCH** `/api/v1/accounts/settings/notifications/update/` - **Permissions**: Authenticated users only ### Privacy Settings - **GET** `/api/v1/accounts/settings/privacy/` - **PATCH** `/api/v1/accounts/settings/privacy/update/` - **Permissions**: Authenticated users only ### Security Settings - **GET** `/api/v1/accounts/settings/security/` - **PATCH** `/api/v1/accounts/settings/security/update/` - **Permissions**: Authenticated users only ### User Statistics - **GET** `/api/v1/accounts/statistics/` - **Permissions**: Authenticated users only - **Returns**: User activity statistics, ride credits, contributions, and achievements ### Top Lists - **GET** `/api/v1/accounts/top-lists/` - **POST** `/api/v1/accounts/top-lists/create/` - **PATCH** `/api/v1/accounts/top-lists/{id}/` - **DELETE** `/api/v1/accounts/top-lists/{id}/delete/` - **Permissions**: Authenticated users only ### Notifications - **GET** `/api/v1/accounts/notifications/` - **PATCH** `/api/v1/accounts/notifications/mark-read/` - **Permissions**: Authenticated users only ### Account Deletion - **POST** `/api/v1/accounts/delete-account/request/` - **POST** `/api/v1/accounts/delete-account/verify/` - **POST** `/api/v1/accounts/delete-account/cancel/` - **Permissions**: Authenticated users only ## Statistics API ### Global Statistics - **GET** `/api/v1/stats/` - **Returns**: Global platform statistics ### Trending Content - **GET** `/api/v1/trending/` - **Query Parameters**: - `content_type`: Filter by content type (parks, rides, reviews) - `time_period`: Time period for trending (24h, 7d, 30d) ### Latest Reviews - **GET** `/api/v1/reviews/latest/` - **Query Parameters**: - `limit`: Number of reviews to return - `park`: Filter by park slug - `ride`: Filter by ride slug ## Error Handling All API endpoints return standardized error responses. The system provides enhanced error handling with detailed messages, error codes, and contextual information. ### Standard Error Response Format ```typescript interface ApiError { status: "error"; error: { code: string; message: string; details?: any; request_user?: string; }; data: null; } ``` ### Enhanced Error Response Format For critical operations like account deletion, the API returns enhanced error responses with additional context: ```typescript interface EnhancedApiError { status: "error"; error: { code: string; message: string; error_code: string; user_info?: { username: string; role: string; is_superuser: boolean; is_staff: boolean; }; help_text?: string; details?: any; request_user?: string; }; data: null; } ``` ### Error Handling in React Components Here's how to handle and display enhanced error messages in your NextJS components: ```typescript import { useState } from 'react'; import { toast } from 'react-hot-toast'; interface ErrorDisplayProps { error: EnhancedApiError | null; onDismiss: () => void; } const ErrorDisplay: React.FC = ({ error, onDismiss }) => { if (!error) return null; const { error: errorData } = error; return (

{errorData.message}

{errorData.error_code && (

Error Code: {errorData.error_code}

)} {errorData.user_info && (

User: {errorData.user_info.username} ({errorData.user_info.role})

{errorData.user_info.is_superuser && (

⚠️ Superuser Account

)}
)} {errorData.help_text && (
Help: {errorData.help_text}
)}
); }; // Usage in account deletion component const AccountDeletionForm: React.FC = () => { const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); const handleDeleteAccount = async () => { setIsLoading(true); setError(null); try { await api.accounts.requestAccountDeletion(); toast.success('Account deletion request submitted successfully'); } catch (err: any) { if (err.response?.data) { const apiError = err.response.data as EnhancedApiError; setError(apiError); // Also show toast for immediate feedback toast.error(apiError.error.message); // Log security-related errors for monitoring if (apiError.error.error_code === 'SUPERUSER_DELETION_BLOCKED') { console.warn('Superuser deletion attempt blocked:', { user: apiError.error.user_info?.username, timestamp: new Date().toISOString() }); } } else { setError({ status: "error", error: { code: "UNKNOWN_ERROR", message: "An unexpected error occurred", error_code: "UNKNOWN_ERROR" }, data: null }); } } finally { setIsLoading(false); } }; return (
setError(null)} />
); }; ``` ### Toast Notifications for Errors For immediate user feedback, combine detailed error displays with toast notifications: ```typescript import { toast } from 'react-hot-toast'; const handleApiError = (error: EnhancedApiError) => { const { error: errorData } = error; // Show immediate toast toast.error(errorData.message, { duration: 5000, position: 'top-right', }); // For critical errors, show additional context if (errorData.error_code === 'SUPERUSER_DELETION_BLOCKED') { toast.error('Superuser accounts cannot be deleted for security reasons', { duration: 8000, icon: '🔒', }); } if (errorData.error_code === 'ADMIN_DELETION_BLOCKED') { toast.error('Admin accounts with staff privileges cannot be deleted', { duration: 8000, icon: '⚠️', }); } }; ``` ### Error Boundary for Global Error Handling Create an error boundary to catch and display API errors globally: ```typescript import React from 'react'; interface ErrorBoundaryState { hasError: boolean; error: EnhancedApiError | null; } class ApiErrorBoundary extends React.Component< React.PropsWithChildren<{}>, ErrorBoundaryState > { constructor(props: React.PropsWithChildren<{}>) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error: any): ErrorBoundaryState { if (error.response?.data?.status === 'error') { return { hasError: true, error: error.response.data as EnhancedApiError }; } return { hasError: true, error: null }; } render() { if (this.state.hasError && this.state.error) { return ( this.setState({ hasError: false, error: null })} /> ); } return this.props.children; } } ``` ### Common Error Codes The system uses specific error codes for different scenarios: - `NOT_AUTHENTICATED`: User not logged in - `PERMISSION_DENIED`: Insufficient permissions - `NOT_FOUND`: Resource not found - `VALIDATION_ERROR`: Invalid request data - `RATE_LIMITED`: Too many requests - `SUPERUSER_DELETION_BLOCKED`: Superuser account deletion attempt - `ADMIN_DELETION_BLOCKED`: Admin account with staff privileges deletion attempt - `ACCOUNT_DELETION_FAILED`: General account deletion failure - `SECURITY_VIOLATION`: Security policy violation detected ### Error Logging and Monitoring For production applications, implement error logging: ```typescript const logError = (error: EnhancedApiError, context: string) => { // Log to your monitoring service (e.g., Sentry, LogRocket) console.error(`API Error in ${context}:`, { code: error.error.code, message: error.error.message, errorCode: error.error.error_code, userInfo: error.error.user_info, timestamp: new Date().toISOString(), context }); // Send to analytics if it's a security-related error if (error.error.error_code?.includes('DELETION_BLOCKED')) { // Track security events analytics.track('Security Event', { event: 'Account Deletion Blocked', errorCode: error.error.error_code, user: error.error.user_info?.username }); } }; ``` ## Pagination List endpoints use cursor-based pagination: ```typescript interface PaginatedResponse { status: "success"; data: { results: T[]; count: number; next: string | null; previous: string | null; }; error: null; } ``` ## Rate Limiting API endpoints are rate limited based on user role: - Anonymous users: 100 requests/hour - Authenticated users: 1000 requests/hour - Moderators: 5000 requests/hour - Admins: 10000 requests/hour ## WebSocket Connections Real-time updates are available for: - Moderation queue updates - New reports and actions - Bulk operation progress - Live statistics updates Connect to: `ws://localhost:8000/ws/moderation/` (requires authentication)