import Foundation enum APIClientError: LocalizedError { case invalidBaseURL case invalidResponse case server(String) var errorDescription: String? { switch self { case .invalidBaseURL: return "API_BASE_URL geçersiz." case .invalidResponse: return "Sunucudan geçerli yanıt alınamadı." case .server(let message): return message } } } final class APIClient { static let shared = APIClient() private init() {} private var baseURL: URL? { guard let raw = Bundle.main.object(forInfoDictionaryKey: "API_BASE_URL") as? String else { return nil } return URL(string: raw) } private var mobileAPIKey: String { Bundle.main.object(forInfoDictionaryKey: "MOBILE_API_KEY") as? String ?? "mobile-dev-key-change-me" } func getInfo(url: String) async throws -> GetInfoResponse { guard let baseURL else { throw APIClientError.invalidBaseURL } var request = URLRequest(url: baseURL.appending(path: "/api/getinfo")) request.httpMethod = "POST" request.timeoutInterval = 20 request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue(mobileAPIKey, forHTTPHeaderField: "X-API-Key") request.httpBody = try JSONEncoder().encode(GetInfoRequest(url: url)) let (data, response) = try await URLSession.shared.data(for: request) guard let http = response as? HTTPURLResponse else { throw APIClientError.invalidResponse } let decoder = JSONDecoder() let envelope = try decoder.decode(APIEnvelope.self, from: data) if (200..<300).contains(http.statusCode), envelope.success, let payload = envelope.data { return payload } if let errorMessage = envelope.error?.message { throw APIClientError.server(errorMessage) } throw APIClientError.server("İstek başarısız oldu (\(http.statusCode)).") } }