221228 TIL [서버로 부터 내려받는 error message다루기(error decoding, enum case의 매개변수(parameter)]

Doogie·2022년 12월 28일
0

회사 어플의 안드로이드 버전을 보면 api통신 에러가 발생했을 때 이렇게 오류가 토스트 메시지로 화면에 표시가 된다
(물론 이렇게 에러메세지를 화면에 바로 표시하는건 썩 그렇게 좋은 방법은 아니라고 생각하지만...)

그치만 난 표시를 하고 자시고를 떠나서 서버로부터 내려오는 JSON형태로 내려오는 에러에 대한 응답값들을 사용할 방법 조차 아예 몰랐었다
(예를 들면 아래와 같은..)

사실 위와 같은 메세지를 다뤄야 '이미 투표가 되었다' 라는 alert을 고객에게 보여줄텐데 그냥 에러났다고 표시할 노릇도 아니고... 어쨌든 문제의 심각성을 깨닫고 어떻게 저 메시지를 다룰 수 있을 지 알아보기 시작!

1. 통신에 실패하더라도 data에는 정보가 들어있다


dataTask의 문서를 보면 request가 성공하든 실패하든 정보를 가지고 있다고 한다
-> 실패한 응답은 에러에 대한 응답값이 들어있으며 통신 실패시 이 응답값을 서버가 내려주는 형대에 맞게 decoding을 하면 될 것이라는 생각

struct ClayfulErrorResponse: Decodable {
    let statusCode: Int
    let error: String
    let message: String
    let errorCode: String
}

그래서 위와같이 서버에서 내려주는 에러메세지 형태에 맞게 decodable 객체를 하나 만들어주고

 guard let status = response.response, (200...299).contains(status.statusCode) else {
     let errorResponse = try JSONDecoder().decode(ClayfulErrorResponse.self, from: response.data ?? Data())
     print(errorResponse)
.
.
.
 }

그리고 위와 같이 status code가 내가 원하는 범위가 벗어날 때 서버로부터 내려오는 에러 메세지를 이 전에 지정해둔 decodable객체로 decoding 해주면 결과는?

아주아주 디코딩이 잘 된다

그럼 이걸 어떻게 다루지...?

2. enum의 case가 parameter를 받도록 하기

나같은 경우 api통신을 할 때 에러를 보통 APIError로 error eunum을 만들어서 사용하는데 이 enum의 case가 parameter를 받을 수 있는 걸 이번에 처음 알았다...ㄷㄷ

enum APIError: Error {
    case transportError
    case responseError(_ errorResponse: ClayfulErrorResponse)
}

위와 같이 responseError case의 경우 errorResponse를 parameter로 받을 수 있다

 guard let status = response.response, (200...299).contains(status.statusCode) else {
     let errorResponse = try JSONDecoder().decode(ClayfulErrorResponse.self, from: response.data ?? Data())
     print(errorResponse)
     throw APIError.responseError(errorResponse)
 }

그럼 이렇게 responseError 를 throw 할 때 1번 과정을 거처 decoding된 errorResponse를 던져준다

        do {
            try await networkManager.request(api)
        } catch let error {
            if let error = error as? APIError {
                switch error {
                case .transportError:
                    return
                case .responseError(let response):
                    debugPrint(response.errorCode) << 요기!
                    return
                }
            }
        }

그리고 do-catch구문에서 error를 catch 하게 된다면 switch문을 통해 해당 에러들을 돌리고 파라미터를 받는 responseError의 경우는 위와 같이 그 객체를 사용 할 수 있다

그럼 이제 여기서부터 에러 응답값을 어떻게 쓸지는 자유!!

profile
끊임없이 문을 여는 개발자

0개의 댓글