diff --git a/Helper/Network Layer/Services/EndPointType.swift b/Helper/Network Layer/Services/EndPointType.swift new file mode 100644 index 0000000..a0b3fdb --- /dev/null +++ b/Helper/Network Layer/Services/EndPointType.swift @@ -0,0 +1,16 @@ +// +// EndPointProtocol.swift +// MapDemoApp +// +// Created by JungpyoHong on 4/25/21. +// + +import Foundation + +protocol EndPointType{ + var baseURL: URL { get } + var path: String { get } + var httpMethod: HTTPMethod { get } + var task: HTTPTask { get } + var headers: HTTPHeaders? { get } +} diff --git a/Helper/Network Layer/Services/HTTPMethod.swift b/Helper/Network Layer/Services/HTTPMethod.swift new file mode 100644 index 0000000..0b4c92b --- /dev/null +++ b/Helper/Network Layer/Services/HTTPMethod.swift @@ -0,0 +1,16 @@ +// +// HTTPMethod.swift +// MapDemoApp +// +// Created by JungpyoHong on 4/25/21. +// + +import Foundation + +public enum HTTPMethod: String { + case get = "GET" + case post = "POST" + case put = "PUT" + case patch = "PATCH" + case delete = "DELETE" +} diff --git a/Helper/Network Layer/Services/HTTPTask.swift b/Helper/Network Layer/Services/HTTPTask.swift new file mode 100644 index 0000000..cf2a7c3 --- /dev/null +++ b/Helper/Network Layer/Services/HTTPTask.swift @@ -0,0 +1,25 @@ +// +// HTTPTask.swift +// MapDemoApp +// +// Created by JungpyoHong on 4/25/21. +// + +import Foundation + +public typealias HTTPHeaders = [String:String] + +public enum HTTPTask { + case request + + case requestParameters(bodyParameters: Parameters?, + bodyEncoding: ParameterEncoding, + urlParameters: Parameters?) + + case requestParametersAndHeaders(bodyParameters: Parameters?, + bodyEncoding: ParameterEncoding, + urlParameters: Parameters?, + additionHeaders: HTTPHeaders?) + + // case download, upload...etc +} diff --git a/Helper/Network Layer/Services/NetworkLogger.swift b/Helper/Network Layer/Services/NetworkLogger.swift new file mode 100644 index 0000000..d398ef0 --- /dev/null +++ b/Helper/Network Layer/Services/NetworkLogger.swift @@ -0,0 +1,40 @@ +// +// NetworkLogger.swift +// MapDemoApp +// +// Created by JungpyoHong on 4/25/21. +// + +import Foundation + +class NetworkLogger { + static func log(request: URLRequest) { + + print("\n - - - - - - - - - - OUTGOING - - - - - - - - - - \n") + defer { print("\n - - - - - - - - - - END - - - - - - - - - - \n") } + + let urlAsString = request.url?.absoluteString ?? "" + let urlComponents = NSURLComponents(string: urlAsString) + + let method = request.httpMethod != nil ? "\(request.httpMethod ?? "")" : "" + let path = "\(urlComponents?.path ?? "")" + let query = "\(urlComponents?.query ?? "")" + let host = "\(urlComponents?.host ?? "")" + + var logOutput = """ + \(urlAsString) \n\n + \(method) \(path)?\(query) HTTP/1.1 \n + HOST: \(host)\n + """ + for (key,value) in request.allHTTPHeaderFields ?? [:] { + logOutput += "\(key): \(value) \n" + } + if let body = request.httpBody { + logOutput += "\n \(NSString(data: body, encoding: String.Encoding.utf8.rawValue) ?? "")" + } + + print(logOutput) + } + + static func log(response: URLResponse) {} +} diff --git a/Helper/Network Layer/Services/NetworkRouter.swift b/Helper/Network Layer/Services/NetworkRouter.swift new file mode 100644 index 0000000..f62ba05 --- /dev/null +++ b/Helper/Network Layer/Services/NetworkRouter.swift @@ -0,0 +1,14 @@ +// +// NetworkRouter.swift +// MapDemoApp +// +// Created by JungpyoHong on 4/25/21. +// + +import Foundation + +protocol NetworkRouter: class { + associatedtype EndPoint: EndPointType + func request(_ route: EndPoint, completion: @escaping NetworkRouterCompletion) + func cancel() +} diff --git a/Helper/Network Layer/Services/Router.swift b/Helper/Network Layer/Services/Router.swift new file mode 100644 index 0000000..0e75bc8 --- /dev/null +++ b/Helper/Network Layer/Services/Router.swift @@ -0,0 +1,115 @@ +// +// Router.swift +// MapDemoApp +// +// Created by JungpyoHong on 4/25/21. +// + +import Foundation + +typealias NetworkRouterCompletion = (Result)->() + +class Router: NetworkRouter { + private var task: URLSessionTask? + private let session = URLSession(configuration: .default) + + func request(_ route: EndPoint, completion: @escaping NetworkRouterCompletion) { + + do { + let request = try self.buildRequest(from: route) + task = session.dataTask(with: request) { data, response, error in + let completionOnMain: (Result) -> Void = { result in + DispatchQueue.main.async { + completion(result) + } + } + guard error == nil else { + completionOnMain(.failure(.serverError)) + return + } + guard let response = response as? HTTPURLResponse else { + completionOnMain(.failure(.badResponse)) + return + } + switch response.statusCode { + case 200...299: + guard let unwrappedData = data else { + completionOnMain(.failure(.noData)) + return + } + do { + let data = try JSONDecoder().decode(T.self, from: unwrappedData) + completionOnMain(.success(data)) + } catch { + print(error) + completionOnMain(.failure(.parseError)) + } + + default: + completionOnMain(.failure(.genericError("Something went wrong"))) + } + } + } catch { + completion(.failure(.badRequest)) + } + task?.resume() + } + func cancel() { + self.task?.cancel() + } + + fileprivate func buildRequest(from route: EndPoint) throws -> URLRequest { + + var request = URLRequest(url: route.baseURL.appendingPathComponent(route.path), + cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, + timeoutInterval: 10.0) + + request.httpMethod = route.httpMethod.rawValue + do { + switch route.task { + case .request: + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + case .requestParameters(let bodyParameters, + let bodyEncoding, + let urlParameters): + + try self.configureParameters(bodyParameters: bodyParameters, + bodyEncoding: bodyEncoding, + urlParameters: urlParameters, + request: &request) + + case .requestParametersAndHeaders(let bodyParameters, + let bodyEncoding, + let urlParameters, + let additionalHeaders): + + self.addAdditionalHeaders(additionalHeaders, request: &request) + try self.configureParameters(bodyParameters: bodyParameters, + bodyEncoding: bodyEncoding, + urlParameters: urlParameters, + request: &request) + } + return request + } catch { + throw error + } + } + + private func configureParameters(bodyParameters: Parameters?, + bodyEncoding: ParameterEncoding, + urlParameters: Parameters?, + request: inout URLRequest) throws { + do { + try bodyEncoding.encode(urlRequest: &request, + bodyParameters: bodyParameters, urlParameters: urlParameters) + } catch { + throw error + } + } + private func addAdditionalHeaders(_ additionalHeaders: HTTPHeaders?, request: inout URLRequest) { + guard let headers = additionalHeaders else { return } + for (key, value) in headers { + request.setValue(value, forHTTPHeaderField: key) + } + } +}