Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PLUB 네트워크 로직 리팩토링 #261

Merged
merged 4 commits into from
Apr 8, 2023
Merged
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
80 changes: 80 additions & 0 deletions PLUB/Sources/Network/Foundation/BaseService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class BaseService {
///
/// 해당 메서드는 검증을 위해 사용됩니다.
/// 요청값을 전달하고 응답받은 값을 처리하고 싶은 경우 `requestObject(_:type:)`을 사용해주세요.
@available(*, deprecated, renamed: "validateHTTPResponse(by:_:type:)")
func evaluateStatus<T: Codable>(
by statusCode: Int,
_ data: Data,
Expand All @@ -51,6 +52,7 @@ class BaseService {
/// - Parameters:
/// - target: Router를 채택한 인스턴스(instance)
/// - type: 응답 값에 들어오는 `data`를 파싱할 모델
@available(*, deprecated, renamed: "sendObservableRequest(_:)")
func sendRequest<T: Codable>(
_ router: Router,
type: T.Type = EmptyModel.self
Expand Down Expand Up @@ -98,6 +100,84 @@ class BaseService {
}
.asObservable()
}


/// Network Response에 대해 검증한 결과값을 리턴합니다.
/// - Parameters:
/// - statusCode: http 상태 코드
/// - data: 응답값으로 받아온 `Data`
/// - type: Data 내부를 구성하는 타입
/// - Returns: GeneralResponse 또는 Plub Error
///
/// 해당 메서드는 검증을 위해 사용됩니다.
/// 서버로부터 값을 받아오거나 받아오지 못했을 때, 성공한 값을 리턴 또는 그에 맞는 PLUB Error를 처리합니다.
private func validateHTTPResponse<T: Codable>(
by statusCode: Int,
_ data: Data,
type: T.Type
) -> Result<GeneralResponse<T>, PLUBError<GeneralResponse<T>>> {
guard let decodedData = try? JSONDecoder().decode(GeneralResponse<T>.self, from: data) else {
return .failure(.decodingError(raw: data))
}
switch statusCode {
case 200..<300 where decodedData.data != nil:
return .success(decodedData)
case 200..<300 where decodedData.data == nil:
return .failure(.decodingError(raw: data))
case 400..<500:
return .failure(.requestError(decodedData))
case 500..<600:
return .failure(.serverError)
default:
return .failure(.unknownedError)
}
}

/// PLUB 서버에 필요한 값을 동봉하여 요청합니다.
/// - Parameters:
/// - target: Router를 채택한 인스턴스(instance)
///
/// 해당 메서드로 파이프라인을 시작하게 되면, [weak self]를 통한 retain cycle를 고려하지 않아도 됩니다.
/// 값을 파이프라인에 전달하게 되면 그 뒤 바로 종료되는 것을 보장하기 때문입니다.
func sendObservableRequest<T: Codable>(_ router: Router) -> Observable<T> {
Single.create { observer in

self.session.request(router).responseData { response in
switch response.result {
case .success(let data):
guard let statusCode = response.response?.statusCode
else {
observer(.failure(PLUBError<T>.unknownedError))
return
}

switch self.validateHTTPResponse(by: statusCode, data, type: T.self) {
case .success(let decodedData):
// validateHTTPResponse에서 success인 경우 Data값을 보장함
observer(.success(decodedData.data!))

case .failure(let error):
observer(.failure(error))
}

case .failure(let error):

switch error {
case .sessionTaskFailed(let urlError as URLError) where urlError.code == .notConnectedToInternet:
// 네트워크 연결이 되어있지 않은 경우
observer(.failure(PLUBError<T>.networkError))

default:
observer(.failure(PLUBError<T>.alamofireError(error))) // Alamofire Error

}
}
}

return Disposables.create()
}
.asObservable()
}
}

// MARK: - Components
Expand Down
29 changes: 29 additions & 0 deletions PLUB/Sources/Network/Foundation/NetworkResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

import Foundation

import enum Alamofire.AFError

@available(*, deprecated)
enum NetworkResult<T> {

/// 성공
Expand All @@ -28,3 +31,29 @@ enum NetworkResult<T> {
/// 경로 에러, path가 잘못된 경우
case pathError
}

/// PLUB 에러 모음
enum PLUBError<T>: Error {

/// 요청 값에 문제가 발생한 경우 발생되는 에러입니다.
///
/// 400~499 대의 응답코드가 이 에러에 속합니다.
case requestError(T)

/// 서버에 문제가 생겼을 때 발생됩니다.
///
/// 500번대 응답코드가 이 에러에 속합니다.
case serverError

/// 사용자의 네트워크에 문제가 있어 값을 가져오지 못하는 경우
case networkError

/// 서버로부터 받아온 값과 Codable 모델 간 디코딩 문제가 발생한 경우
case decodingError(raw: Data)

/// Alamofire에서 직접 내려주는 에러
case alamofireError(AFError)

/// 알 수 없는 에러
case unknownedError
}