# API Configuration for MangaReader iOS App ## Overview This directory contains the API configuration for connecting the iOS app to the VPS backend. The configuration is centralized in `APIConfig.swift` and includes all necessary settings for API communication. ## Files - **APIConfig.swift**: Main configuration file with all API settings, endpoints, and helper methods - **APIConfigExample.swift**: Comprehensive usage examples and demonstrations - **README.md** (this file): Documentation and usage guide ## Current Configuration ### Server Connection - **Server URL**: `https://gitea.cbcren.online` - **Port**: `3001` - **Full Base URL**: `https://gitea.cbcren.online:3001` - **API Version**: `v1` - **API Base Path**: `https://gitea.cbcren.online:3001/api/v1` ### Timeouts - **Default Request Timeout**: `30.0` seconds (for regular API calls) - **Resource Download Timeout**: `300.0` seconds (5 minutes, for large downloads) ### Retry Policy - **Max Retries**: `3` attempts - **Base Retry Delay**: `1.0` second (with exponential backoff) ### Cache Configuration - **Max Memory Usage**: `100` cached responses - **Cache Expiry**: `300.0` seconds (5 minutes) ## Usage ### Basic URL Construction ```swift // Method 1: Use the helper function let url = APIConfig.url(for: "manga/popular") // Result: "https://gitea.cbcren.online:3001/manga/popular" // Method 2: Get a URL object if let urlObj = APIConfig.urlObject(for: "manga/popular") { var request = URLRequest(url: urlObj) // Make request... } // Method 3: Use predefined endpoints let endpoint = APIConfig.Endpoints.download(mangaSlug: "one-piece", chapterNumber: 1089) // Result: "https://gitea.cbcren.online:3001/api/v1/download/one-piece/1089" ``` ### URLSession Configuration ```swift let configuration = URLSessionConfiguration.default configuration.timeoutIntervalForRequest = APIConfig.defaultTimeout configuration.timeoutIntervalForResource = APIConfig.downloadTimeout let session = URLSession(configuration: configuration) ``` ### URLRequest with Headers ```swift var request = URLRequest(url: url) request.timeoutInterval = APIConfig.defaultTimeout // Add common headers for (key, value) in APIConfig.commonHeaders { request.setValue(value, forHTTPHeaderField: key) } // Add authentication if needed if let token = authToken { let authHeaders = APIConfig.authHeader(token: token) for (key, value) in authHeaders { request.setValue(value, forHTTPHeaderField: key) } } ``` ## Available Endpoints ### Download Endpoints ```swift // Request chapter download APIConfig.Endpoints.download(mangaSlug: "one-piece", chapterNumber: 1089) // Check if chapter is downloaded APIConfig.Endpoints.checkDownloaded(mangaSlug: "one-piece", chapterNumber: 1089) // List all downloaded chapters for a manga APIConfig.Endpoints.listChapters(mangaSlug: "one-piece") // Get specific image from chapter APIConfig.Endpoints.getImage(mangaSlug: "one-piece", chapterNumber: 1089, pageIndex: 0) // Delete a chapter APIConfig.Endpoints.deleteChapter(mangaSlug: "one-piece", chapterNumber: 1089) ``` ### Server Endpoints ```swift // Get storage statistics APIConfig.Endpoints.storageStats() // Health check APIConfig.Endpoints.health() ``` ## Environment Configuration The configuration includes presets for different environments: ### Development ```swift APIConfig.development // - serverURL: "http://192.168.1.100" // - port: 3001 // - timeout: 60.0s // - logging: true ``` ### Staging ```swift APIConfig.staging // - serverURL: "https://staging.cbcren.online" // - port: 3001 // - timeout: 30.0s // - logging: true ``` ### Production (Current) ```swift APIConfig.production // - serverURL: "https://gitea.cbcren.online" // - port: 3001 // - timeout: 30.0s // - logging: false ``` ### Testing (Debug Only) ```swift #if DEBUG APIConfig.testing // - serverURL: "http://localhost:3001" // - port: 3001 // - timeout: 5.0s // - logging: true #endif ``` ## Changing the Server URL To change the API server URL, modify the `serverURL` property in `APIConfig.swift`: ```swift // In APIConfig.swift, line 37 static let serverURL = "https://gitea.cbcren.online" // Change this ``` For environment-specific URLs, use compile-time conditionals: ```swift #if DEBUG static let serverURL = "http://192.168.1.100" // Local development #else static let serverURL = "https://gitea.cbcren.online" // Production #endif ``` ## Error Codes The API defines specific error codes for different scenarios: ```swift APIConfig.ErrorCodes.chapterNotFound // 40401 APIConfig.ErrorCodes.chapterAlreadyDownloaded // 40901 APIConfig.ErrorCodes.storageLimitExceeded // 50701 APIConfig.ErrorCodes.invalidImageFormat // 42201 APIConfig.ErrorCodes.downloadFailed // 50001 ``` ## Validation The configuration includes a validation method: ```swift if APIConfig.isValid { print("Configuration is valid") } else { print("Configuration is invalid") } ``` This checks: - Server URL is not empty - Port is in valid range (1-65535) - Timeout values are positive - Retry count is non-negative ## Debug Support In debug builds, you can print the current configuration: ```swift #if DEBUG APIConfig.printConfiguration() #endif ``` This outputs: ``` === API Configuration === Server URL: https://gitea.cbcren.online Port: 3001 Base URL: https://gitea.cbcren.online:3001 API Version: v1 Default Timeout: 30.0s Download Timeout: 300.0s Max Retries: 3 Logging Enabled: false Cache Enabled: true ========================= ``` ## Best Practices 1. **Always use predefined endpoints** when available instead of manually constructing URLs 2. **Use appropriate timeouts** - `defaultTimeout` for regular calls, `downloadTimeout` for large downloads 3. **Validate configuration** on app startup 4. **Use the helper methods** (`url()`, `urlObject()`) for URL construction 5. **Include common headers** in all requests 6. **Handle specific error codes** defined in `APIConfig.ErrorCodes` 7. **Enable logging only in debug builds** for security ## Example: Making an API Call ```swift func fetchPopularManga() async throws -> [Manga] { // Construct URL guard let url = APIConfig.urlObject(for: "manga/popular") else { throw APIError.invalidURL } // Create request var request = URLRequest(url: url) request.timeoutInterval = APIConfig.defaultTimeout // Add headers for (key, value) in APIConfig.commonHeaders { request.setValue(value, forHTTPHeaderField: key) } // Make request let (data, response) = try await URLSession.shared.data(for: request) // Validate response guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { throw APIError.requestFailed } // Decode response let mangas = try JSONDecoder().decode([Manga].self, from: data) return mangas } ``` ## Example: Downloading with Retry ```swift func downloadChapterWithRetry( mangaSlug: String, chapterNumber: Int ) async throws -> Data { let endpoint = APIConfig.Endpoints.download( mangaSlug: mangaSlug, chapterNumber: chapterNumber ) return try await fetchWithRetry(endpoint: endpoint, retryCount: 0) } func fetchWithRetry(endpoint: String, retryCount: Int) async throws -> Data { guard let url = URL(string: endpoint), retryCount < APIConfig.maxRetries else { throw APIError.retryLimitExceeded } var request = URLRequest(url: url) request.timeoutInterval = APIConfig.downloadTimeout do { let (data, response) = try await URLSession.shared.data(for: request) if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 { return data } else { throw APIError.requestFailed } } catch { // Calculate exponential backoff delay let delay = APIConfig.baseRetryDelay * pow(2.0, Double(retryCount)) try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000)) return try await fetchWithRetry(endpoint: endpoint, retryCount: retryCount + 1) } } ``` ## Troubleshooting ### Connection Issues 1. **Verify server URL**: Check that `serverURL` is correct and accessible 2. **Check port**: Ensure `port` matches the backend server configuration 3. **Test connectivity**: Use the health endpoint: `APIConfig.Endpoints.health()` 4. **Enable logging**: Set `loggingEnabled = true` to see request details ### Timeout Issues 1. **For regular API calls**: Use `APIConfig.defaultTimeout` (30 seconds) 2. **For large downloads**: Use `APIConfig.downloadTimeout` (300 seconds) 3. **Slow networks**: Increase timeout values if needed ### SSL Certificate Issues If using HTTPS with a self-signed certificate: 1. Add the certificate to the app's bundle 2. Configure URLSession to trust the certificate 3. Or use HTTP for development (not recommended for production) ## Migration Notes When migrating from the old configuration: 1. Replace hardcoded URLs with `APIConfig.url(for:)` or predefined endpoints 2. Use `APIConfig.commonHeaders` instead of manually setting headers 3. Replace hardcoded timeouts with `APIConfig.defaultTimeout` or `APIConfig.downloadTimeout` 4. Add validation on app startup with `APIConfig.isValid` 5. Use specific error codes from `APIConfig.ErrorCodes` ## Additional Resources - See `APIConfigExample.swift` for more comprehensive examples - Check the backend API documentation for available endpoints - Review the iOS app's Services directory for integration examples