diff --git a/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPClient.swift b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPClient.swift index b82db11..68c3934 100644 --- a/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPClient.swift +++ b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPClient.swift @@ -9,12 +9,22 @@ import Foundation public class HTTPClient { + private var interceptors: [HTTPInterceptor] = [] + + public init(interceptors: [HTTPInterceptor]) { + self.interceptors = interceptors + } + public func jsonRequest( - target: HTTPConnectTarget, - timeoutInterval: TimeInterval = 0, - completionHandler: @escaping (Result<[String: Any], HTTPError>) -> Void + target: HTTPConnectTarget, + timeoutInterval: TimeInterval = 0, + interceptor: HTTPInterceptor, + completionHandler: @escaping (Result<[String: Any], HTTPError>) -> Void ) { - request(target: target) { result in + request( + target: target, + interceptor: interceptor + ) { result in switch result { case let .success(value): completionHandler(.success(value.toJsonDictionary())) @@ -25,44 +35,65 @@ public class HTTPClient { } public func request( - target: HTTPConnectTarget, - timeoutInterval: TimeInterval = 0, - completionHandler: @escaping (Result) -> Void - ) { - - let url = URL(string: + target: HTTPConnectTarget, + timeoutInterval: TimeInterval = 0, + interceptor: HTTPInterceptor, + completionHandler: @escaping (Result) -> Void + ) { + let finalInterceptors = interceptors + [interceptor] + + let url = URL(string: target.baseURL + - target.path + - target.parameters.queryString - ) - - guard let url = url else { - assertionFailure("Invalid url") - return - } - - var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: timeoutInterval) - request.httpBody = target.parameters.body?.toJsonData() - - - URLSession.shared.dataTask( - with: request) { data, response, error in - if let error = error { - completionHandler(.failure(.undefined(error))) - return - } - if let response = response as? HTTPURLResponse, - !(200...299).contains(response.statusCode) { - completionHandler(.failure(.failureStatusCode(response.statusCode))) - return - } - guard let data = data else { - completionHandler(.failure(.emptyData)) - return - } - - completionHandler(.success(data)) + target.path + + target.parameters.queryString + ) + + guard let url = url else { + assertionFailure("Invalid url") + return } + + var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: timeoutInterval) + request.httpBody = target.parameters.body?.toJsonData() + + request = finalInterceptors.reduce(request) { $1.resetRequest(request: $0, target: target) } + + + finalInterceptors + .forEach { $0.willSendRequest() } + + URLSession.shared.dataTask( + with: request) { data, response, error in + guard let response = response else { + assertionFailure("response data does not exist") + return + } + + if let error = error { + + completionHandler( + finalInterceptors.reduce(.failure(.undefined(error))) {$1.didReceiveResponse(result: ($0, response), target: target)} + ) + return + } + if let response = response as? HTTPURLResponse, + !(200...299).contains(response.statusCode) { + completionHandler( + finalInterceptors.reduce(.failure(.failureStatusCode(response.statusCode))) {$1.didReceiveResponse(result: ($0, response), target: target)} + ) + return + } + guard let data = data else { + completionHandler(.failure(.emptyData)) + return + } + + completionHandler( + finalInterceptors.reduce(.success(data)) { $1.didReceiveResponse(result: ($0, response), target: target) } + ) + } + + finalInterceptors.forEach { $0.didSendRequest() } } } diff --git a/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPInterceptor.swift b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPInterceptor.swift new file mode 100644 index 0000000..e0b5ef3 --- /dev/null +++ b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPInterceptor.swift @@ -0,0 +1,35 @@ +// +// HTTPInterceptor.swift +// HelpMeChooseIOS +// +// Created by CanlabLee on 2022/06/05. +// Copyright © 2022 JYKang. All rights reserved. +// + +import Foundation.NSURLRequest + +public protocol HTTPInterceptor { + func resetRequest( + request: URLRequest, + target: HTTPConnectTarget + ) -> URLRequest + func willSendRequest() + func didSendRequest() + func didReceiveResponse( + result: Result, + target: HTTPConnectTarget + ) -> Result +} + +extension HTTPInterceptor { + public func resetRequest( + request: URLRequest, + target: HTTPConnectTarget + ) -> URLRequest { return request } + public func willSendRequest() {} + public func didSendRequest() {} + public func didReceiveResponse( + result: Result, + target: HTTPConnectTarget + ) -> Result { return result } +} diff --git a/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPParameter.swift b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPParameter.swift index 968bee0..c8d3c3d 100644 --- a/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPParameter.swift +++ b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/HTTPParameter.swift @@ -33,7 +33,7 @@ extension HTTPParameter { .components(separatedBy: ",") .reduce("") { $0 + toQuery(key: key, value: $1) } } else { - query += toQuery(key: key, value: valueString) + query = toQuery(key: key, value: valueString) } result += query diff --git a/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/Interceptor/HTTPInterceptor.swift b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/Interceptor/HTTPInterceptor.swift new file mode 100644 index 0000000..3bfa617 --- /dev/null +++ b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/Interceptor/HTTPInterceptor.swift @@ -0,0 +1,37 @@ +// +// HTTPInterceptor.swift +// HelpMeChooseIOS +// +// Created by CanlabLee on 2022/06/05. +// Copyright © 2022 JYKang. All rights reserved. +// + +import Foundation.NSURLRequest +import Foundation.NSURLResponse + +public protocol HTTPInterceptor { + func resetRequest( + request: URLRequest, + target: HTTPConnectTarget + ) -> URLRequest + func willSendRequest() + func didSendRequest() + func didReceiveResponse( + result: (Result, URLResponse), + target: HTTPConnectTarget + ) -> Result +} + +extension HTTPInterceptor { + public func resetRequest( + request: URLRequest, + target: HTTPConnectTarget + ) -> URLRequest { return request } + public func willSendRequest() {} + public func didSendRequest() {} + public func didReceiveResponse( + result: (Result, URLResponse), + target: HTTPConnectTarget + ) -> Result { return result.0 } +} + diff --git a/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/Interceptor/TokenInjectInterceptor.swift b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/Interceptor/TokenInjectInterceptor.swift new file mode 100644 index 0000000..52f9e21 --- /dev/null +++ b/Targets/HelpMeChooseIOS/Sources/Infrastructure/Network/Interceptor/TokenInjectInterceptor.swift @@ -0,0 +1,43 @@ +// +// TokenInjectInterceptor.swift +// HelpMeChooseIOS +// +// Created by CanlabLee on 2022/06/05. +// Copyright © 2022 JYKang. All rights reserved. +// + +import Foundation + +public enum AcessToken { + case bearer(String) + case custom(String) + + public var value: String { + switch self { + case let .bearer(value): return "Bearer \(value)" + case let .custom(value): return value + } + } +} + +public class TokenInjectInterceptor: HTTPInterceptor { + private let headerFieldKey = "Authorization" + let token: () -> AcessToken + + public init(token: @escaping () -> AcessToken) { + self.token = token + } + public func resetRequest( + request: URLRequest, + target: HTTPConnectTarget + ) -> URLRequest { + let token = token() + var newRequest = request + + if token.value == request.value(forHTTPHeaderField: headerFieldKey){ return request } + + newRequest.setValue(token.value, forHTTPHeaderField: headerFieldKey) + + return newRequest + } +}