반응형
네트워크 응답의 Raw JSON 데이터를 로깅을 할때, 함수를 통해서 네트워크 요청 클래스에서 진행을 하는데 문뜩 Single로 네트워크 통신을 주로(사실은 다) 처리하니까. Single에 Extension으로 추가해서 조금 더 보기 좋게 할 수 있지 않을까? 해서 해보았습니다.
Single Extension 구현
import RxSwift
extension PrimitiveSequence where Trait == SingleTrait, Element: DataResponse {
/// Raw JSON을 로깅하는 확장 메서드
/// - Parameter tag: 로그 태그
/// - Returns: 로깅이 적용된 Single
func logRawJSON(tag: String = "Raw JSON Response") -> Single<Element> {
return self.do(onSuccess: { response in
#if DEBUG
if let jsonString = String(data: response.data, encoding: .utf8) {
log.debug("\(tag): \(jsonString)")
} else {
log.error("응답 데이터를 문자열로 변환하는 데 실패했습니다.")
}
#endif
}, onError: { error in
#if DEBUG
log.error("로깅 중 에러 발생: \(error.localizedDescription)")
#endif
})
}
}
위 코드에서는 RxSwift의 PrimitiveSequence를 확장하여 Single 타입에 로깅 기능을 추가하고 있습니다.
주요 부분을 하나씩 살펴보겠습니다.
1. 확장 조건
extension PrimitiveSequence where Trait == SingleTrait, Element: DataResponse
- Trait == SingleTrait: Single 타입에만 확장을 적용합니다.
- Element: DataResponse: 응답 데이터가 DataResponse 타입이어야 합니다.
2. logRawJSON 메서드
func logRawJSON(tag: String = "Raw JSON Response") -> Single<Element>
- tag: 로그에 사용할 태그를 지정할 수 있으며, 기본값은 "Raw JSON Response"입니다.
- 반환 타입은 로깅이 적용된 Single<Element>입니다.
3. 로깅 구현
return self.do(onSuccess: { response in
#if DEBUG
if let jsonString = String(data: response.data, encoding: .utf8) {
log.debug("\(tag): \(jsonString)")
} else {
log.error("응답 데이터를 문자열로 변환하는 데 실패했습니다.")
}
#endif
}, onError: { error in
#if DEBUG
log.error("로깅 중 에러 발생: \(error.localizedDescription)")
#endif
})
- do(onSuccess:onError:): Single의 성공 및 에러 이벤트를 가로채어 추가 작업을 수행합니다.
- #if DEBUG: 디버그 모드에서만 로깅이 수행되도록 조건부 컴파일을 사용합니다.
- 성공 시 응답 데이터를 문자열로 변환하여 디버그 로그로 출력합니다. 변환에 실패하면 에러 로그를 출력합니다.
- 에러 시 에러 메시지를 로그로 남깁니다.
사용 예시
이해를 위한 예시
import RxSwift
import Alamofire
struct APIService {
static func fetchData() -> Single<DataResponse> {
return Single<DataResponse>.create { single in
let request = AF.request("https://api.example.com/data")
.response { response in
switch response.result {
case .success(let data):
single(.success(response))
case .failure(let error):
single(.failure(error))
}
}
return Disposables.create {
request.cancel()
}
}
}
}
// 사용 예시
APIService.fetchData()
.logRawJSON(tag: "API Fetch Data")
.subscribe(onSuccess: { response in
// 성공 처리
}, onFailure: { error in
// 에러 처리
})
.disposed(by: disposeBag)
제 실제 프로젝트 코드입니다.
func fetchSafeAreaList(start: Coordinate, goal: Coordinate, route: Route) -> Single<SafeAreaListInfo> {
let startCoord = "\(start.lat),\(start.lon)"
let goalCoord = "\(goal.lat),\(goal.lon)"
return network
.request(.fetchSafeAreaList(start: startCoord, goal: goalCoord, highWayInfo: route.trafast[0].highWayInfos))
.logRawJSON()// <---- 이친구 입니다.
.map { response -> SafeAreaDTO in
do {
let decoder = JSONDecoder()
let decodedResponse = try decoder.decode([SafeAreaDTO].self, from: response.data) // 배열로 디코딩
if let firstSafeArea = decodedResponse.first {
return firstSafeArea
} else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "No SafeAreaDTO found"))
}
} catch {
log.error("Decoding error: \(error)")
if let jsonString = String(data: response.data, encoding: .utf8) {
log.error("Received JSON: \(jsonString)")
}
throw error
}
}
.map { $0.toDomain() }
.do(onSuccess: { (route) in
log.debug("response fetchSafeAreaList \(route)")
}, onError: { error in
log.error("Error occurred during fetchSafeAreaList request: \(error.localizedDescription)")
})
}
결과값
이렇게 로그가 잘 찍히는걸 확인 할 수 있습니다
반응형
'iOS > RxSwift' 카테고리의 다른 글
[RxCocoa] 델레게이트와 Rx의 중첩으로 인한 셀 클릭 인지 안되는현상 (0) | 2024.11.12 |
---|---|
[RxSwift] withUnretained 를 대체하는 subscribe(with:onNext:) (0) | 2024.10.28 |
[RxSwift] PrimitiveSequenceType (0) | 2024.09.30 |
[RxSwift] Merge와 concat (0) | 2024.09.19 |
[RxSwift] 재사용으로 인해, 테이블뷰 셀안에 버튼이 반응하지 않을때 (0) | 2024.07.10 |