awesome-ios-developer/Helper/Network Layer/Services/Router.swift

112 lines
4.2 KiB
Swift
Raw Normal View History

2021-05-03 13:34:53 +07:00
//
// Router.swift
2021-05-20 11:16:36 +07:00
//
2021-05-03 13:34:53 +07:00
//
2021-05-20 11:16:36 +07:00
// Created by JungpyoHong on 5/11/21.
2021-05-03 13:34:53 +07:00
//
import Foundation
2021-05-20 11:16:36 +07:00
typealias NetworkRouterCompletion<T> = (Result<T, AppError>) -> Void
2021-05-03 13:34:53 +07:00
class Router<EndPoint: EndPointType>: NetworkRouter {
private var task: URLSessionTask?
private let session = URLSession(configuration: .default)
2021-05-20 11:16:36 +07:00
func cancel() {
self.task?.cancel()
}
2021-05-03 13:34:53 +07:00
func request<T: Decodable>(_ route: EndPoint, completion: @escaping NetworkRouterCompletion<T>) {
do {
let request = try self.buildRequest(from: route)
task = session.dataTask(with: request) { data, response, error in
let completionOnMain: (Result<T, AppError>) -> 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))
}
2021-05-20 11:16:36 +07:00
self.task?.resume()
2021-05-03 13:34:53 +07:00
}
2021-05-03 13:49:36 +07:00
private func buildRequest(from route: EndPoint) throws -> URLRequest {
2021-05-03 13:34:53 +07:00
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")
2021-05-20 11:16:36 +07:00
case .requestParameters(let (bodyParameters, urlParameters)):
2021-05-03 13:34:53 +07:00
try self.configureParameters(bodyParameters: bodyParameters,
urlParameters: urlParameters,
request: &request)
2021-05-20 11:16:36 +07:00
case .requestParametersAndHeaders(let (bodyParameters,
urlParameters,
additionalHeaders)):
2021-05-03 13:34:53 +07:00
self.addAdditionalHeaders(additionalHeaders, request: &request)
try self.configureParameters(bodyParameters: bodyParameters,
urlParameters: urlParameters,
request: &request)
}
return request
} catch {
throw error
}
}
private func configureParameters(bodyParameters: Parameters?,
urlParameters: Parameters?,
request: inout URLRequest) throws {
do {
2021-05-20 11:16:36 +07:00
if let bodyParameters = bodyParameters {
try JSONParameterEncoder.encode(urlRequest: &request, with: bodyParameters)
}
if let urlParameters = urlParameters {
try URLParameterEncoder.encode(urlRequest: &request, with: urlParameters)
}
2021-05-03 13:34:53 +07:00
} catch {
throw error
}
}
2021-05-03 13:49:36 +07:00
2021-05-03 13:34:53 +07:00
private func addAdditionalHeaders(_ additionalHeaders: HTTPHeaders?, request: inout URLRequest) {
guard let headers = additionalHeaders else { return }
for (key, value) in headers {
request.setValue(value, forHTTPHeaderField: key)
}
}
}