import Foundation public class Api { private var session: URLSession public static let shared = Api() public init(session: URLSession? = nil) { if let session = session { self.session = session } else { let sessionConfig = URLSessionConfiguration.default sessionConfig.timeoutIntervalForRequest = 60.0 sessionConfig.timeoutIntervalForResource = 60.0 self.session = URLSession(configuration: sessionConfig) } } // MARK: - Private wrappres private func genError(_ msg: String, suggestion: String, code: Int = 0) -> Error { return NSError(domain: "", code: code, userInfo: [NSLocalizedDescriptionKey: msg, NSLocalizedRecoverySuggestionErrorKey: suggestion]) } private func createRequest(api: String, method: String, body: B? = nil, params: [String:P]? = nil) -> URLRequest? where B: Encodable, P: LosslessStringConvertible { guard var urlComponents = URLComponents(string: Constants.baseUrl + api) else { return nil } if let params = params, method.uppercased() == "GET" { urlComponents.queryItems = params.map { URLQueryItem(name: $0, value: String($1)) } } var request = URLRequest(url: urlComponents.url!) request.httpMethod = method request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("application/json", forHTTPHeaderField: "Accept") request.addValue("Bearer " + Settings.shared.user.token, forHTTPHeaderField: "Authorization") if let body = body, method.uppercased() != "GET" { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted if let data = try? encoder.encode(body) { request.httpBody = data } } return request } private func makeRequest(api: String, method: String = "GET", body: B?, params: [String:P]? = nil) async throws -> T where T: Decodable, B: Encodable, P: LosslessStringConvertible { guard let request = self.createRequest(api: api, method: method, body: body, params: params) else { throw self.genError("Error creating request", suggestion: "") } let (data, response) = try await self.session.data(for: request) // let str = String(data: data, encoding: .utf8) // print("================================") // if let string = str?.replacingOccurrences(of: "\\\"", with: "\"") // .replacingOccurrences(of: "\\'", with: "'") // .replacingOccurrences(of: "\\n", with: "") { // print(string) // } // print("================================") do { let resp = try JSONDecoder().decode(Response.self, from: data) if resp.success { return resp.data! } else { throw self.genError(resp.error!, suggestion: "") } } catch let error as Swift.DecodingError { throw CocoaError.error((error as CustomDebugStringConvertible).debugDescription) } catch { throw error } } private func makeGetRequest(api: String, params:[String: P]? = nil) async throws -> T where T: Decodable, P: LosslessStringConvertible { return try await self.makeRequest(api: api, method: "GET", body: nil as Int?, params: params) } private func makeEmptyGetRequest(api: String) async throws -> T where T: Decodable { return try await self.makeRequest(api: api, method: "GET", body: nil as Int?, params: nil as [String:Int]?) } private func makeEmptyBodyRequest(api: String, method: String = "POST") async throws -> T where T: Decodable { return try await self.makeRequest(api: api, method: method, body: nil as Int?, params: nil as [String:Int]?) } private func makeBodyRequest(api: String, body: B?, method: String = "POST") async throws -> T where T: Decodable, B: Encodable { return try await self.makeRequest(api: api, method: method, body: body, params: nil as [String:Int]?) } // MARK: - AutoCat public API public static func login(email: String, password: String) async throws -> User { let body = [ "email": email, "password": password ] return try await self.shared.makeBodyRequest(api: "user/login", body: body) } }