// // Network.swift // Werkout_ios // // Created by Trey Tartt on 6/19/23. // import Foundation enum BaseURLs: String { case local = "http://127.0.0.1:8000" case dev = "https://dev.werkout.fitness" static var currentBaseURL: String { return BaseURLs.dev.rawValue } } enum FetchableError: Error { case apiError(Error) case noData case decodeError(Error) case endOfFileError case noPostData case noToken case statusError(Int, String?) } protocol Fetchable { associatedtype Response: Codable var attachToken: Bool { get } var baseURL: String { get } var endPoint: String { get } func fetch(completion: @escaping (Result) -> Void) } protocol Postable: Fetchable { var postableData: [String: Any]? { get } var successStatus: Int { get } } extension Fetchable { var baseURL: String { BaseURLs.currentBaseURL } var attachToken: Bool { return true } func fetch(completion: @escaping (Result) -> Void) { let url = URL(string: baseURL+endPoint)! var request = URLRequest(url: url,timeoutInterval: Double.infinity) if attachToken { guard let token = UserStore.shared.token else { completion(.failure(.noPostData)) return } request.addValue(token, forHTTPHeaderField: "Authorization") } request.addValue("application/json", forHTTPHeaderField: "Content-Type") let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in if let error = error { completion(.failure(.apiError(error))) return } guard let data = data else { completion(.failure(.noData)) return } do { let model = try JSONDecoder().decode(Response.self, from: data) completion(.success(model)) return } catch { completion(.failure(.decodeError(error))) return } }) task.resume() } } extension Postable { func fetch(completion: @escaping (Result) -> Void) { guard let postableData = postableData else { completion(.failure(.noPostData)) return } let url = URL(string: baseURL+endPoint)! let postData = try! JSONSerialization.data(withJSONObject:postableData) var request = URLRequest(url: url,timeoutInterval: Double.infinity) if attachToken { guard let token = UserStore.shared.token else { completion(.failure(.noPostData)) return } request.addValue(token, forHTTPHeaderField: "Authorization") } request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" request.httpBody = postData let task = URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in if let error = error { completion(.failure(.apiError(error))) return } if let httpRespone = response as? HTTPURLResponse { if httpRespone.statusCode != successStatus { var returnStr: String? if let data = data { returnStr = String(data: data, encoding: .utf8) } completion(.failure(.statusError(httpRespone.statusCode, returnStr))) return } } guard let data = data else { completion(.failure(.noData)) return } do { let model = try JSONDecoder().decode(Response.self, from: data) completion(.success(model)) return } catch { completion(.failure(.decodeError(error))) return } }) task.resume() } }