Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
Expand All @@ -25,44 +35,65 @@ public class HTTPClient {
}

public func request(
target: HTTPConnectTarget,
timeoutInterval: TimeInterval = 0,
completionHandler: @escaping (Result<Data, HTTPError>) -> Void
) {

let url = URL(string:
target: HTTPConnectTarget,
timeoutInterval: TimeInterval = 0,
interceptor: HTTPInterceptor,
completionHandler: @escaping (Result<Data, HTTPError>) -> 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() }
}

}
Original file line number Diff line number Diff line change
@@ -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<Success>(
result: Result<Success, HTTPError>,
target: HTTPConnectTarget
) -> Result<Success, HTTPError>
}

extension HTTPInterceptor {
public func resetRequest(
request: URLRequest,
target: HTTPConnectTarget
) -> URLRequest { return request }
public func willSendRequest() {}
public func didSendRequest() {}
public func didReceiveResponse<Success>(
result: Result<Success, HTTPError>,
target: HTTPConnectTarget
) -> Result<Success, HTTPError> { return result }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Data, HTTPError>, URLResponse),
target: HTTPConnectTarget
) -> Result<Data, HTTPError>
}

extension HTTPInterceptor {
public func resetRequest(
request: URLRequest,
target: HTTPConnectTarget
) -> URLRequest { return request }
public func willSendRequest() {}
public func didSendRequest() {}
public func didReceiveResponse(
result: (Result<Data, HTTPError>, URLResponse),
target: HTTPConnectTarget
) -> Result<Data, HTTPError> { return result.0 }
}

Original file line number Diff line number Diff line change
@@ -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
}
}