Skip to content

Commit

Permalink
Improved Error Handling Core api
Browse files Browse the repository at this point in the history
  • Loading branch information
Mehran Kamalifard authored and Mehran Kamalifard committed Aug 19, 2024
1 parent 08e64c4 commit fc26dfb
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 20 deletions.
4 changes: 4 additions & 0 deletions EasyCrypto.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
A81742E0297E593D00023B28 /* EasyCryptoUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81742DF297E593D00023B28 /* EasyCryptoUITestsLaunchTests.swift */; };
A82CB994298A7A5500699C22 /* Publisher + Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82CB993298A7A5500699C22 /* Publisher + Extension.swift */; };
A82CB996298A7AB900699C22 /* URLRequest + Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82CB995298A7AB900699C22 /* URLRequest + Extension.swift */; };
A8450C932C72FC0F002A3D24 /* APIErrorResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8450C922C72FC0F002A3D24 /* APIErrorResponse.swift */; };
A851A20C29890B4D007F4CF9 /* NetworkClientProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A851A20A29890B4C007F4CF9 /* NetworkClientProtocol.swift */; };
A851A20D29890B4D007F4CF9 /* NetworkClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = A851A20B29890B4D007F4CF9 /* NetworkClient.swift */; };
A851A21029890B75007F4CF9 /* NetworkClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A851A20F29890B75007F4CF9 /* NetworkClientManager.swift */; };
Expand Down Expand Up @@ -253,6 +254,7 @@
A81742DF297E593D00023B28 /* EasyCryptoUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EasyCryptoUITestsLaunchTests.swift; sourceTree = "<group>"; };
A82CB993298A7A5500699C22 /* Publisher + Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Publisher + Extension.swift"; sourceTree = "<group>"; };
A82CB995298A7AB900699C22 /* URLRequest + Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLRequest + Extension.swift"; sourceTree = "<group>"; };
A8450C922C72FC0F002A3D24 /* APIErrorResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIErrorResponse.swift; sourceTree = "<group>"; };
A851A20A29890B4C007F4CF9 /* NetworkClientProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkClientProtocol.swift; sourceTree = "<group>"; };
A851A20B29890B4D007F4CF9 /* NetworkClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkClient.swift; sourceTree = "<group>"; };
A851A20F29890B75007F4CF9 /* NetworkClientManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkClientManager.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -978,6 +980,7 @@
A851A22629890C0A007F4CF9 /* APIError.swift */,
A851A22729890C0B007F4CF9 /* APIDebuger.swift */,
A851A22529890C0A007F4CF9 /* Configuration.swift */,
A8450C922C72FC0F002A3D24 /* APIErrorResponse.swift */,
);
path = Utility;
sourceTree = "<group>";
Expand Down Expand Up @@ -1224,6 +1227,7 @@
A851A21529890B9F007F4CF9 /* NetworkTarget + Default.swift in Sources */,
02F1EEF429CDAE0E003AD8A9 /* CoreDataManager.swift in Sources */,
02D986142996AA320070A7E0 /* SearchMarketRepository.swift in Sources */,
A8450C932C72FC0F002A3D24 /* APIErrorResponse.swift in Sources */,
A851A21429890B9F007F4CF9 /* NetworkTarget.swift in Sources */,
A851A20D29890B4D007F4CF9 /* NetworkClient.swift in Sources */,
459B45D12A0BBCD3001C93BA /* Double + Extension.swift in Sources */,
Expand Down
38 changes: 22 additions & 16 deletions EasyCrypto/Core/Networking/Client/NetworkClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ final class NetworkClient: NetworkClientProtocol {
/// - session: The URLSession to use. Default: `URLSession.shared`.
/// - logging: The logging utility to use. Default: `APIDebugger()`.
///
let session: URLSession
var session: URLSession {
let configuration = URLSessionConfiguration.default
configuration.waitsForConnectivity = true
return URLSession(configuration: configuration)
}

let logging: Logging

init(session: URLSession = .shared, logging: Logging = APIDebugger()) {
self.session = session
init(logging: Logging = APIDebugger()) {
self.logging = logging
}

Expand All @@ -33,8 +37,21 @@ final class NetworkClient: NetworkClientProtocol {
self.logging.logRequest(request: urlRequest)
return publisher(request: urlRequest)
.receive(on: scheduler)
.tryMap { result, _ -> Data in
return result
.tryMap { result, response -> Data in
guard let httpResponse = response as? HTTPURLResponse else {
throw APIError.invalidResponse(httpStatusCode: 0)
}

if httpResponse.isResponseOK {
return result
} else {
// Attempt to decode error response
if let apiErrorResponse = try? decoder.decode(APIErrorResponse.self, from: result) {
throw APIError.statusMessage(message: apiErrorResponse.status.errorMessage)
} else {
throw APIError.invalidResponse(httpStatusCode: httpResponse.statusCode)
}
}
}
.decode(type: type.self, decoder: decoder)
.mapError { error in
Expand All @@ -52,17 +69,6 @@ final class NetworkClient: NetworkClientProtocol {
.mapError { APIError.urlError($0) }
.flatMap { response -> AnyPublisher<(data: Data, response: URLResponse), APIError> in
self.logging.logResponse(response: response.response, data: response.data)
guard let httpResponse = response.response as? HTTPURLResponse else {
return Fail(error: APIError.invalidResponse(httpStatusCode: 0))
.eraseToAnyPublisher()
}

if !httpResponse.isResponseOK {
let error = NetworkClient.errorType(type: httpResponse.statusCode)
return Fail(error: error)
.eraseToAnyPublisher()
}

return Just(response)
.setFailureType(to: APIError.self)
.eraseToAnyPublisher()
Expand Down
24 changes: 24 additions & 0 deletions EasyCrypto/Core/Networking/Utility/APIErrorResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// APIErrorResponse.swift
// EasyCrypto
//
// Created by Mehran Kamalifard on 2024/08/19.
//

import Foundation

struct APIErrorResponse: Decodable {

let status: Status
}

struct Status: Decodable {

let errorCode: Int
let errorMessage: String

private enum CodingKeys: String, CodingKey {
case errorCode = "error_code"
case errorMessage = "error_message"
}
}
8 changes: 8 additions & 0 deletions EasyCrypto/Presentation/CoinDetail/View/CoinDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ struct CoinDetailView: Coordinatable {
}
.padding(.top)
}
Spacer()
if presentAlert {
CustomAlertView(title: viewModel.errorTitle,
message: alertMessage ,
primaryButtonLabel: "Ok") {
self.presentAlert = false
}
}
}
}
.navigationBarTitle(String.empty)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ protocol DefaultCoinDetailViewModel: CoinDetailViewModelProtocol { }
final class CoinDetailViewModel: DefaultViewModel, DefaultCoinDetailViewModel {

private let coinDetailUsecase: CoinDetailUsecaseProtocol

let errorTitle: String = Constants.Title.errorTitle

@Published private(set) var coinData: CoinUnit?
@Published var isShowActivity: Bool = false

var navigateSubject = PassthroughSubject<CoinDetailView.Routes, Never>()

Expand Down Expand Up @@ -50,11 +51,9 @@ extension CoinDetailViewModel: DataFlowProtocol {

func getCoinDetailData(id: String) {
guard !id.isEmpty else { return }
isShowActivity = true
call(argument: coinDetailUsecase.execute(id: id)) { [weak self] data in
guard let data = data else { return }
self?.coinData = data
self?.isShowActivity = false
}
}
}
2 changes: 1 addition & 1 deletion EasyCrypto/Presentation/Main/View/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ extension MainView {
extension MainView {
func showAlert(_ title: String, _ message: String) -> some View {
CustomAlertView(title: title, message: message, primaryButtonLabel: "Retry", primaryButtonAction: {
self.presentAlert = true
self.presentAlert = false
self.viewModel.callFirstTime()
})
.previewLayout(.sizeThatFits)
Expand Down

0 comments on commit fc26dfb

Please sign in to comment.