diff --git a/Climeet-iOS/Climeet-iOS.xcodeproj/project.pbxproj b/Climeet-iOS/Climeet-iOS.xcodeproj/project.pbxproj index e914b17..0d9dd11 100644 --- a/Climeet-iOS/Climeet-iOS.xcodeproj/project.pbxproj +++ b/Climeet-iOS/Climeet-iOS.xcodeproj/project.pbxproj @@ -558,7 +558,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Climeet-iOS/Preview Content\""; - DEVELOPMENT_TEAM = 7MJ69FU8BU; + DEVELOPMENT_TEAM = L56LNTR7PZ; ENABLE_PREVIEWS = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -594,7 +594,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Climeet-iOS/Preview Content\""; - DEVELOPMENT_TEAM = 7MJ69FU8BU; + DEVELOPMENT_TEAM = L56LNTR7PZ; ENABLE_PREVIEWS = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; diff --git a/Climeet-iOS/Climeet-iOS/App/Climeet_iOSApp.swift b/Climeet-iOS/Climeet-iOS/App/Climeet_iOSApp.swift index e483295..0054de5 100644 --- a/Climeet-iOS/Climeet-iOS/App/Climeet_iOSApp.swift +++ b/Climeet-iOS/Climeet-iOS/App/Climeet_iOSApp.swift @@ -17,7 +17,6 @@ struct ClimeetiOSApp: App { KeyChain.shared.refreshToken = Env.MASTER_TOKEN // 테스트 값 설정 // print(KeyChain.shared.refreshToken) // 값 읽어오기 // KeyChain.shared.deleteRefreshToken() // 리프레시 토큰 초기화(테스트메서드) - configureAPIClient() applyGlobalNavigationTitleAttributes() } @@ -34,8 +33,4 @@ struct ClimeetiOSApp: App { // Font.climeetFontTitle4 해당함 ] } - - func configureAPIClient() { - APIClient.shared.configure(tokenRefresher: TokenRefresher()) - } } diff --git a/Climeet-iOS/Climeet-iOS/Data/Client/ClimberClient.swift b/Climeet-iOS/Climeet-iOS/Data/Client/ClimberClient.swift index 3964678..7958426 100644 --- a/Climeet-iOS/Climeet-iOS/Data/Client/ClimberClient.swift +++ b/Climeet-iOS/Climeet-iOS/Data/Client/ClimberClient.swift @@ -76,7 +76,7 @@ extension ClimberClient: DependencyKey { }, login: { param in let endPoint = ClimberEndPoint.login(param) - return try await APIClient.shared.request(endPoint, decode: SignResponse.self) + return try await APIClient(session: .default, tokenRefresher: nil).request(endPoint, decode: SignResponse.self) } ) } diff --git a/Climeet-iOS/Climeet-iOS/Data/Common/APIClient+Extension.swift b/Climeet-iOS/Climeet-iOS/Data/Common/APIClient+Extension.swift new file mode 100644 index 0000000..c53b319 --- /dev/null +++ b/Climeet-iOS/Climeet-iOS/Data/Common/APIClient+Extension.swift @@ -0,0 +1,14 @@ +// +// APIClient+Extension.swift +// Climeet-iOS +// +// Created by 송형욱 on 12/18/24. +// + +import Foundation +import Alamofire +import NetworkKit + +extension APIClient { + static let shared: APIClient = APIClient(session: .default, tokenRefresher: TokenRefresher()) +} diff --git a/NetworkKit/Sources/NetworkKit/Kit/APIClient.swift b/NetworkKit/Sources/NetworkKit/Kit/APIClient.swift index d09389e..aa75255 100644 --- a/NetworkKit/Sources/NetworkKit/Kit/APIClient.swift +++ b/NetworkKit/Sources/NetworkKit/Kit/APIClient.swift @@ -2,33 +2,21 @@ import Foundation import Alamofire public final class APIClient: APIProtocol, @unchecked Sendable { + private let session: Session - public static let shared = APIClient() - private var tokenRefresher: TokenRefreshable? - private var isConfigured = false - - private init() { } - - private lazy var session: Session = { - let configuration = URLSessionConfiguration.af.default - configuration.waitsForConnectivity = true - configuration.timeoutIntervalForRequest = 60 // seconds that a task will wait for data to arrive - configuration.timeoutIntervalForResource = 300 // seconds for whole resource request to complete ,. - return Session( - configuration: configuration, - interceptor: tokenRefresher.map { APIInterceptor(tokenRefresher: $0) }, - eventMonitors: [APILogger()] - ) - }() - - public func configure(tokenRefresher: TokenRefreshable) { - guard !isConfigured else { - print("APIClient는 이미 초기화 되었습니다.") - return + public init(session: Session, tokenRefresher: TokenRefreshable?) { + if let tokenRefresher { + self.session = Session( + configuration: session.sessionConfiguration, + interceptor: APIInterceptor(tokenRefresher: tokenRefresher), + eventMonitors: [APILogger()] + ) + } else { + self.session = Session( + configuration: session.sessionConfiguration, + eventMonitors: [APILogger()] + ) } - - self.tokenRefresher = tokenRefresher - self.isConfigured = true } public func request(_ endpoint: Endpoint, decode: T.Type) async throws -> T { diff --git a/NetworkKit/Sources/NetworkKit/Kit/APIInterceptor.swift b/NetworkKit/Sources/NetworkKit/Kit/APIInterceptor.swift index 8dd6a57..b150edc 100644 --- a/NetworkKit/Sources/NetworkKit/Kit/APIInterceptor.swift +++ b/NetworkKit/Sources/NetworkKit/Kit/APIInterceptor.swift @@ -20,7 +20,11 @@ final class APIInterceptor: RequestInterceptor { let token = tokenRefresher.readToken() guard !token.isEmpty else { - completion(.failure(APIError(errorCode: "401 Token Error", message: "Token Missing"))) + completion(.failure(APIError( + statusCode: 401, + errorCode: "401 Token Error", + message: "Token Missing" + ))) return } @@ -34,7 +38,11 @@ final class APIInterceptor: RequestInterceptor { } func retry(_ request: Request, for session: Session, dueTo error: any Error, completion: @escaping @Sendable (RetryResult) -> Void) { - + guard let response = request.task?.response as? HTTPURLResponse, + response.statusCode == 401 else { + completion(.doNotRetryWithError(error)) + return + } let retryLimit = 3 guard request.retryCount < retryLimit else { completion(.doNotRetry) diff --git a/NetworkKit/Sources/NetworkKit/Kit/APILogger.swift b/NetworkKit/Sources/NetworkKit/Kit/APILogger.swift index 0031a69..d34beef 100644 --- a/NetworkKit/Sources/NetworkKit/Kit/APILogger.swift +++ b/NetworkKit/Sources/NetworkKit/Kit/APILogger.swift @@ -6,7 +6,7 @@ struct APILogger: EventMonitor { func requestDidFinish(_ request: Request) { #if DEBUG - print("🚀 NETWORK Reqeust LOG") + print("🚀 NETWORK Request LOG") print(request.description) print( @@ -22,12 +22,20 @@ struct APILogger: EventMonitor { func request(_ request: DataRequest, didParseResponse response: DataResponse) { #if DEBUG print("✅ NETWORK Response LOG") - print( - "URL: " + (request.request?.url?.absoluteString ?? "nil") + "\n" - + "Result: " + "\(response.result)" + "\n" - + "StatusCode: " + "\(response.response?.statusCode ?? 0)" + "\n" - + "Data: \(response.data?.prettyJson ?? "nil")" - ) + switch response.result { + case let .success(data): + print( + "URL: " + (request.request?.url?.absoluteString ?? "nil") + "\n" + + "Result: " + "\(data)" + "\n" + + "StatusCode: " + "\(response.response?.statusCode ?? 0)" + ) + case let .failure(error): + print( + "URL: " + (request.request?.url?.absoluteString ?? "nil") + "\n" + + "Result: " + "\(error.localizedDescription)" + "\n" + + "StatusCode: " + "\(response.response?.statusCode ?? 0)" + ) + } #endif } } diff --git a/NetworkKit/Sources/NetworkKit/Kit/EndPoint.swift b/NetworkKit/Sources/NetworkKit/Kit/EndPoint.swift index 97ba593..358ca46 100644 --- a/NetworkKit/Sources/NetworkKit/Kit/EndPoint.swift +++ b/NetworkKit/Sources/NetworkKit/Kit/EndPoint.swift @@ -13,7 +13,7 @@ public protocol Endpoint: URLRequestConvertible { extension Endpoint { private var defaultHeaders: HTTPHeaders { - var headers: HTTPHeaders = [] + var headers: HTTPHeaders = [.contentType("application/json")] if let token = token { headers.add(.authorization(bearerToken: token))