# API Integration Infrastructure - Worker App

## Overview

Comprehensive HTTP client infrastructure built with **Dio** and **Riverpod 3.0** for the Worker Flutter application. This setup provides robust API integration with authentication, caching, retry logic, error handling, and offline support.

## Architecture

```
lib/core/network/
├── dio_client.dart          # Main HTTP client with Riverpod providers
├── api_interceptor.dart     # Authentication, logging, and error interceptors
├── network_info.dart        # Network connectivity monitoring
├── api_constants.dart       # API endpoints and configuration
├── exceptions.dart          # Custom exception definitions
└── failures.dart            # Domain-level failure types
```

## Key Features

### 1. Dio HTTP Client (`dio_client.dart`)

**DioClient Class**
- Wrapper around Dio with full method support (GET, POST, PUT, PATCH, DELETE)
- File upload with multipart/form-data
- File download with progress tracking
- Cache management utilities

**Riverpod Providers**
- `dioProvider` - Configured Dio instance with all interceptors
- `dioClientProvider` - DioClient wrapper instance
- `cacheStoreProvider` - Hive-based cache storage
- `cacheOptionsProvider` - Cache configuration

**Configuration**
- Base URL: Configurable per environment (dev/staging/prod)
- Timeouts: 30s connection, 30s receive, 30s send
- Headers: JSON content-type, Vietnamese language by default
- Cache: 7-day max-stale, no caching on auth errors (401, 403)

### 2. Interceptors (`api_interceptor.dart`)

#### AuthInterceptor
- **Token Injection**: Automatically adds Bearer token to requests
- **Token Refresh**: Handles 401 errors with automatic token refresh
- **Public Endpoints**: Skips auth for login/OTP/register endpoints
- **Language Header**: Adds Vietnamese language preference
- **Storage**: Uses SharedPreferences for token persistence

#### LoggingInterceptor
- **Request Logging**: Method, URL, headers, body, query parameters
- **Response Logging**: Status code, response data (truncated)
- **Error Logging**: Error type, status code, error data
- **Security**: Sanitizes sensitive fields (password, OTP, tokens)
- **Format**: Beautiful formatted logs with separators

#### ErrorTransformerInterceptor
- **Dio Error Mapping**: Transforms DioException to custom exceptions
- **Status Code Handling**:
  - 400 → ValidationException/BadRequestException
  - 401 → UnauthorizedException/TokenExpiredException/InvalidOTPException
  - 403 → ForbiddenException
  - 404 → NotFoundException
  - 409 → ConflictException
  - 422 → ValidationException with field errors
  - 429 → RateLimitException with retry-after
  - 5xx → ServerException/ServiceUnavailableException
- **Connection Errors**: Timeout, NoInternet, etc.

#### RetryInterceptor
- **Exponential Backoff**: Configurable delay multiplier
- **Max Retries**: 3 attempts by default
- **Retry Conditions**:
  - Connection timeout/errors
  - 5xx server errors (except 501)
  - 408 Request Timeout
  - 429 Too Many Requests
- **Network Check**: Verifies connectivity before retrying

### 3. Network Monitoring (`network_info.dart`)

**NetworkInfo Interface**
- Connection status checking
- Connection type detection (WiFi, Mobile, Ethernet, etc.)
- Real-time connectivity monitoring via Stream

**NetworkStatus Class**
- Connection state (connected/disconnected)
- Connection type
- Timestamp
- Convenience methods (isWiFi, isMobile, isMetered)

**Riverpod Providers**
- `networkInfoProvider` - NetworkInfo implementation
- `isConnectedProvider` - Current connection status
- `connectionTypeProvider` - Current connection type
- `networkStatusStreamProvider` - Stream of status changes
- `NetworkStatusNotifier` - Reactive network status state

### 4. Error Handling

**Exceptions (`exceptions.dart`)**
- NetworkException - Base network error
- NoInternetException - No connectivity
- TimeoutException - Connection timeout
- ServerException - 5xx errors
- ServiceUnavailableException - 503 errors
- AuthException - Authentication errors (401, 403)
- ValidationException - Request validation errors
- NotFoundException - 404 errors
- ConflictException - 409 errors
- RateLimitException - 429 errors
- PaymentException - Payment-related errors
- CacheException - Cache errors
- StorageException - Local storage errors
- ParseException - JSON parsing errors

**Failures (`failures.dart`)**
- Immutable Freezed classes for domain-level errors
- User-friendly Vietnamese error messages
- Properties:
  - `message` - Display message
  - `isCritical` - Requires immediate attention
  - `canRetry` - Can be retried
  - `statusCode` - HTTP status if available

### 5. API Constants (`api_constants.dart`)

**Configuration**
- Base URLs (dev, staging, production)
- API version prefix (/v1)
- Timeout durations (30s)
- Retry configuration (3 attempts, exponential backoff)
- Cache durations (24h products, 1h profile, 48h categories)
- Request headers (JSON, Vietnamese language)

**Endpoints**
- Authentication: /auth/request-otp, /auth/verify-otp, /auth/register, etc.
- Loyalty: /loyalty/points, /loyalty/rewards, /loyalty/referral, etc.
- Products: /products, /products/search, /categories, etc.
- Orders: /orders, /payments, etc.
- Projects & Quotes: /projects, /quotes, etc.
- Chat: /chat/messages, /ws/chat (WebSocket)
- Account: /profile, /addresses, etc.
- Promotions & Notifications

## Usage Examples

### Basic GET Request

```dart
// Using DioClient with Riverpod
final dioClient = ref.watch(dioClientProvider);

try {
  final response = await dioClient.get(
    ApiConstants.getProducts,
    queryParameters: {'page': '1', 'limit': '20'},
  );

  final products = response.data;
} on NoInternetException catch (e) {
  // Handle no internet
} on ServerException catch (e) {
  // Handle server error
}
```

### POST Request with Authentication

```dart
final dioClient = ref.watch(dioClientProvider);

try {
  final response = await dioClient.post(
    ApiConstants.createOrder,
    data: {
      'items': [...],
      'deliveryAddress': {...},
      'paymentMethod': 'COD',
    },
  );

  final order = Order.fromJson(response.data);
} on ValidationException catch (e) {
  // Handle validation errors
  print(e.errors); // Map<String, List<String>>
}
```

### File Upload

```dart
final dioClient = ref.watch(dioClientProvider);

final formData = FormData.fromMap({
  'name': 'John Doe',
  'avatar': await MultipartFile.fromFile(
    filePath,
    filename: 'avatar.jpg',
  ),
});

try {
  final response = await dioClient.uploadFile(
    ApiConstants.uploadAvatar,
    formData: formData,
    onSendProgress: (sent, total) {
      print('Upload progress: ${(sent / total * 100).toStringAsFixed(0)}%');
    },
  );
} catch (e) {
  // Handle error
}
```

### Network Status Monitoring

```dart
// Check current connection status
final isConnected = await ref.watch(isConnectedProvider.future);

if (!isConnected) {
  // Show offline message
}

// Listen to connection changes
ref.listen(
  networkStatusStreamProvider,
  (previous, next) {
    next.whenData((status) {
      if (status.isConnected) {
        // Back online - sync data
      } else {
        // Offline - show message
      }
    });
  },
);
```

### Cache Management

```dart
final dioClient = ref.watch(dioClientProvider);

// Clear all cache
await dioClient.clearCache();

// Clear specific endpoint cache
await dioClient.clearCacheByPath(ApiConstants.getProducts);

// Force refresh from network
final response = await dioClient.get(
  ApiConstants.getProducts,
  options: ApiRequestOptions.forceNetwork.toDioOptions(),
);

// Use cache-first strategy
final response = await dioClient.get(
  ApiConstants.getCategories,
  options: ApiRequestOptions.cached.toDioOptions(),
);
```

### Custom Error Handling

```dart
try {
  final response = await dioClient.post(...);
} on ValidationException catch (e) {
  // Show field-specific errors
  e.errors?.forEach((field, messages) {
    print('$field: ${messages.join(", ")}');
  });
} on RateLimitException catch (e) {
  // Show rate limit message
  if (e.retryAfter != null) {
    print('Try again in ${e.retryAfter} seconds');
  }
} on TokenExpiredException catch (e) {
  // Token refresh failed - redirect to login
  ref.read(authProvider.notifier).logout();
} catch (e) {
  // Generic error
  print('Error: $e');
}
```

## Dependencies

```yaml
dependencies:
  dio: ^5.4.3+1                                    # HTTP client
  connectivity_plus: ^6.0.3                        # Network monitoring
  pretty_dio_logger: ^1.3.1                        # Request/response logging
  dio_cache_interceptor: ^3.5.0                    # Response caching
  dio_cache_interceptor_hive_store: ^3.2.2         # Hive storage for cache
  flutter_riverpod: ^3.0.0                         # State management
  riverpod_annotation: ^3.0.0                      # Code generation
  shared_preferences: ^2.2.3                       # Token storage
  path_provider: ^2.1.3                            # Cache directory
  freezed_annotation: ^3.0.0                       # Immutable models
```

## Configuration

### Environment-Specific Base URLs

Update `ApiConstants.baseUrl` based on build flavor:

```dart
// For dev environment
static const String baseUrl = devBaseUrl;

// For production
static const String baseUrl = prodBaseUrl;
```

### Timeout Configuration

Adjust timeouts in `ApiConstants`:

```dart
static const Duration connectionTimeout = Duration(milliseconds: 30000);
static const Duration receiveTimeout = Duration(milliseconds: 30000);
static const Duration sendTimeout = Duration(milliseconds: 30000);
```

### Retry Configuration

Customize retry behavior in `ApiConstants`:

```dart
static const int maxRetryAttempts = 3;
static const Duration initialRetryDelay = Duration(milliseconds: 1000);
static const Duration maxRetryDelay = Duration(milliseconds: 5000);
static const double retryDelayMultiplier = 2.0;
```

### Cache Configuration

Adjust cache settings in `cacheOptionsProvider`:

```dart
CacheOptions(
  store: store,
  maxStale: const Duration(days: 7),
  hitCacheOnErrorExcept: [401, 403],
  priority: CachePriority.high,
  allowPostMethod: false,
);
```

## Testing

### Connection Testing

```dart
// Test network connectivity
final networkInfo = ref.watch(networkInfoProvider);
final isConnected = await networkInfo.isConnected;
final connectionType = await networkInfo.connectionType;

print('Connected: $isConnected');
print('Type: ${connectionType.displayNameVi}');
```

### API Endpoint Testing

```dart
// Test authentication endpoint
try {
  final response = await dioClient.post(
    ApiConstants.requestOtp,
    data: {'phone': '+84912345678'},
  );
  print('OTP sent successfully');
} catch (e) {
  print('Failed: $e');
}
```

## Best Practices

1. **Always use DioClient**: Don't create raw Dio instances
2. **Handle specific exceptions**: Catch specific error types for better UX
3. **Check connectivity**: Verify network status before critical requests
4. **Use cache strategically**: Cache static data (categories, products)
5. **Monitor network changes**: Listen to connectivity stream for sync
6. **Clear cache appropriately**: Clear on logout, version updates
7. **Log in debug only**: Disable logging in production
8. **Sanitize sensitive data**: Never log passwords, tokens, OTP codes
9. **Use retry wisely**: Don't retry POST/PUT/DELETE by default
10. **Validate responses**: Check response.data structure before parsing

## Future Enhancements

- [ ] Offline request queue implementation
- [ ] Request deduplication
- [ ] GraphQL support
- [ ] WebSocket integration for real-time chat
- [ ] Certificate pinning for security
- [ ] Request compression (gzip)
- [ ] Multi-part upload progress
- [ ] Background sync when network restored
- [ ] Advanced caching strategies (stale-while-revalidate)
- [ ] Request cancellation tokens

## Troubleshooting

### Issue: Token Refresh Loop

**Solution**: Check refresh token expiry and clear auth data if expired

### Issue: Cache Not Working

**Solution**: Verify CacheStore initialization and directory permissions

### Issue: Network Detection Fails

**Solution**: Add required permissions to AndroidManifest.xml and Info.plist

### Issue: Timeout on Large Files

**Solution**: Increase timeout or use download with progress callback

### Issue: Interceptor Order Matters

**Current Order**:
1. Logging (first - logs everything)
2. Auth (adds tokens)
3. Cache (caches responses)
4. Retry (retries failures)
5. Error Transformer (last - transforms errors)

## Support

For issues or questions about the API integration:
- Check logs for detailed error information
- Verify network connectivity using NetworkInfo
- Review interceptor configuration
- Check API endpoint constants

---

**Generated for Worker App**
Version: 1.0.0
Last Updated: 2025-10-17
