🎯 Changes: - Moved from gitea.cbcren.online to manga.cbcren.online - Updated Caddy proxy configuration with SSL auto-cert - Updated iOS app APIConfig to use HTTPS - Changed port from 3001 to standard HTTPS (443) - No interference with Gitea or other services 🔧 Technical Details: - DNS: manga.cbcren.online → 194.163.191.200 - Proxy: Caddy with automatic HTTPS - Backend: 172.17.0.1:3001 (Docker gateway) - SSL: Automatic Let's Encrypt certificate ✅ Tested: - Health check: https://manga.cbcren.online/api/health ✓ - Storage stats: https://manga.cbcren.online/api/storage/stats ✓ - HTTPS redirect working correctly ✓ 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
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.0seconds (for regular API calls) - Resource Download Timeout:
300.0seconds (5 minutes, for large downloads)
Retry Policy
- Max Retries:
3attempts - Base Retry Delay:
1.0second (with exponential backoff)
Cache Configuration
- Max Memory Usage:
100cached responses - Cache Expiry:
300.0seconds (5 minutes)
Usage
Basic URL Construction
// 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
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = APIConfig.defaultTimeout
configuration.timeoutIntervalForResource = APIConfig.downloadTimeout
let session = URLSession(configuration: configuration)
URLRequest with Headers
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
// 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
// Get storage statistics
APIConfig.Endpoints.storageStats()
// Health check
APIConfig.Endpoints.health()
Environment Configuration
The configuration includes presets for different environments:
Development
APIConfig.development
// - serverURL: "http://192.168.1.100"
// - port: 3001
// - timeout: 60.0s
// - logging: true
Staging
APIConfig.staging
// - serverURL: "https://staging.cbcren.online"
// - port: 3001
// - timeout: 30.0s
// - logging: true
Production (Current)
APIConfig.production
// - serverURL: "https://gitea.cbcren.online"
// - port: 3001
// - timeout: 30.0s
// - logging: false
Testing (Debug Only)
#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:
// In APIConfig.swift, line 37
static let serverURL = "https://gitea.cbcren.online" // Change this
For environment-specific URLs, use compile-time conditionals:
#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:
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:
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:
#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
- Always use predefined endpoints when available instead of manually constructing URLs
- Use appropriate timeouts -
defaultTimeoutfor regular calls,downloadTimeoutfor large downloads - Validate configuration on app startup
- Use the helper methods (
url(),urlObject()) for URL construction - Include common headers in all requests
- Handle specific error codes defined in
APIConfig.ErrorCodes - Enable logging only in debug builds for security
Example: Making an API Call
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
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
- Verify server URL: Check that
serverURLis correct and accessible - Check port: Ensure
portmatches the backend server configuration - Test connectivity: Use the health endpoint:
APIConfig.Endpoints.health() - Enable logging: Set
loggingEnabled = trueto see request details
Timeout Issues
- For regular API calls: Use
APIConfig.defaultTimeout(30 seconds) - For large downloads: Use
APIConfig.downloadTimeout(300 seconds) - Slow networks: Increase timeout values if needed
SSL Certificate Issues
If using HTTPS with a self-signed certificate:
- Add the certificate to the app's bundle
- Configure URLSession to trust the certificate
- Or use HTTP for development (not recommended for production)
Migration Notes
When migrating from the old configuration:
- Replace hardcoded URLs with
APIConfig.url(for:)or predefined endpoints - Use
APIConfig.commonHeadersinstead of manually setting headers - Replace hardcoded timeouts with
APIConfig.defaultTimeoutorAPIConfig.downloadTimeout - Add validation on app startup with
APIConfig.isValid - Use specific error codes from
APIConfig.ErrorCodes
Additional Resources
- See
APIConfigExample.swiftfor more comprehensive examples - Check the backend API documentation for available endpoints
- Review the iOS app's Services directory for integration examples