https://ios-development.tistory.com/731
해당 게시글을 토대로 구현해본 네트워크 레이어를 기록해봅니다.
부족한 점이 있다면 알려주시면 감사합니다.
1. 에러 처리
* HTTP통신은 비연결성 통신으로 통신의 응답, 오류만을 방출하면 되도록 Single로 구현하였습니다.
* Loading은 액티비티 인디케이터 관련 클래스입니다. 나중에 기록해보도록 하겠습니다.
public func request<T: Decodable>(_ urlConvertible: URLRequestConvertible) -> Single<T> {
return Single.create { single in
Loading.start()
let request = self.session
.request(urlConvertible,
interceptor: self.authInterceptor)
.validate(statusCode: 200 ..< 300)
.responseDecodable(of: T.self) { response in
switch response.result {
case let .success(data):
single(.success(data))
case let .failure(error):
if let errorData = response.data {
do {
// 백엔드와 통신하고 에러가 발생했다면 ErrorEntity와 같은 구조로 response가 내려옵니다.
// 이 error response를 ErrorEntity로 디코딩합니다.
let networkError = try JSONDecoder().decode(ErrorEntity.self, from: errorData)
// 이 ErrorEntity를 활용해 APIError라는 Error를 만듭니다.
let apiError = APIError(error: networkError)
single(.failure(apiError))
} catch {
// 디코딩 과정에 에러가 발생한 경우 디코딩 에러를 리턴합니다
single(.failure(APIError.decodingError)
}
} else {
// 기본 에러를 방출합니다.
single(.failure(error))
}
}
Loading.stop()
}
return Disposables.create {
request.cancel()
}
}
}
대부분의 경우 API에러의 network로 생성되어 statusCode(ex: 401 400 409)를 갖게되고,
errorMessage를 연관값으로 갖고있게됩니다.
에러가 발생한 경우 사용자가 무슨에러인지 알아야 하기 때문에 이렇게 처리했습니다.
만약 에러가 발생한다면?
flatMap에서 네트워크 통신을 하고 통신의 결과를 리턴할 때 만약 에러가 발생되어서 onError(failure)가 방출된다면 더이상 이벤트를 방출할 수 없게 됩니다. 그래서 catch블록에서 에러를 다른 서브젝트(릴레이)로 넘기고 .empty()를 리턴합니다.
self?.error는 다음과 같습니다
Error를 방출하는 서브젝트 또는 릴레이입니다.
어떤 행위의 결과로 에러를 방출해야할 때 해당 서브젝트로 에러를 전달합니다.
onError가 아닌 onNext로 에러를 방출합니다.
그럼 뷰 컨트롤러에서는 다음 에러를 받아서 처리하게됩니다.
여기서 presentErrorAlert라는 메서드를 띄우게 되는데 해당 부분에서 에러를 구분해 에러에 따른 알럿을 띄웁니다.
errorDescription은 APIError의 선언부에 나와있습니다.
케이스에 default로 작성해줘도 되지만 에러가 추가될 것 같아서 합치진 않았습니다.
다음엔 토큰관리 부분을 기록해보겠습니다.