Alamofire를 사용할 때 서버에서 에러 응답을 받을 경우, AFError 내부에서 response body를 직접 받을 수 없었음... 하지만 response.data에서 직접 처리해야 한다는 점을 발견!
API 요청 중 에러가 발생했을 때, 서버에서 아래와 같은 JSON 형식으로 응답이 옴
{
"Code": 1,
"Message": "에러메시지 입니다."
}
하지만 AFError에서는 이 응답 데이터를 직접 못받았음..
String으로 변환하면 아래와 같이 응답이 와서, 원하는 응답이 아니였다
{"timestamp":1735176875297,"status":500,"error":"Internal Server Error","path":"/path"}
찾아본 결과error response body를 error가 아닌 response.data에서 처리해야했음
CustomAFError 정의CustomAFError 구조체를 만들어 AFError가 responseData를 가질 수 있도록 확장struct CustomAFError: Error {
let underlyingError: AFError
let responseData: Data?
let errorCode: Int?
}
Codable로 변환할 수 있도록 모델 정의struct APIError: Codable {
let code: String
let message: String
}
AFError 확장AFError를 확장responseData, errorCode를 가져오고, APIError를 디코딩하는 기능 추가extension AFError {
var responseData: Data? {
switch self {
case let .responseValidationFailed(reason):
if case let .customValidationFailed(error as CustomAFError) = reason {
return error.responseData
}
case let .sessionTaskFailed(error as CustomAFError):
return error.responseData
case let .responseSerializationFailed(_):
return nil
default:
if let error = self.underlyingError as? CustomAFError {
return error.responseData
}
}
return nil
}
var errorCode: Int? {
switch self {
case let .responseValidationFailed(reason):
if case let .customValidationFailed(error as CustomAFError) = reason {
return error.errorCode
}
case let .sessionTaskFailed(error as CustomAFError):
return error.errorCode
case let .responseSerializationFailed(_):
return 111111
default:
if let error = self.underlyingError as? CustomAFError {
return error.errorCode
}
}
return nil
}
func decodedAPIError() -> APIError? {
guard let data = self.responseData else { return nil }
return decodeAPIError(from: data)
}
func decodeAPIError(from data: Data?) -> APIError? {
guard let data = data else { return nil }
do {
let decoder = JSONDecoder()
return try decoder.decode(APIError.self, from: data)
} catch {
print("Failed to decode APIError: \\(error)")
return nil
}
}
}
fetch 함수에서 AFError를 감싸 CustomAFError로 변환AFError에 포함func fetch(completion: @escaping (Result<Data, AFError>) -> Void) {
let url = "url"
var params: Parameter = [:]
params["param"] = "param"
NetworkManager.shared.request(url, method: .post, parameters: params, headers: registerDeviceHttpHeaders) { response in
switch response.result {
case .success:
// 성공 처리
completion(.success(response.data ?? Data()))
case .failure(let error):
if response.data == nil {
return completion(.failure(error))
} else {
let customError = AFError.responseValidationFailed(reason: .customValidationFailed(error: CustomAFError(underlyingError: error, responseData: response.data, errorCode: error.responseCode)))
return completion(.failure(customError))
}
}
}
}
decodedAPIError()를 활용하여 응답 데이터를 처리할 수 있도록 handleError 함수 구현 (공통 처리를 위해서 진행)private func fetchFunc(completion: @escaping (Result<Data, ErrorMessage>) -> Void) {
getRepository.fetch { result in
switch result {
case .success(let data):
// 성공 처리
completion(.success(data))
case .failure(let error):
self.handleError(error: error, completion: completion)
}
}
}
private func handleError(error: AFError, completion: @escaping (Result<Data, ErrorMessage>) -> Void) {
guard let errorData = error.decodedAPIError() else {
// error.decodedAPIError()가 nil일 경우 처리
return
}
// error.decodedAPIError()가 있을 경우 로그 출력
print("errorData.code", errorData.code)
print("errorData.message", errorData.message)
}
AFError 자체에서는 responseData를 직접 받을 수 없음response.data에서 응답 데이터를 확인해야 함CustomAFError를 정의하여 AFError 내부에서 응답 데이터를 관리할 수 있도록 확장decodedAPIError()를 활용하여 JSON 데이터를 디코딩하고 활용 가능Alamofire에서 발생하는 에러를 보다 효율적으로 관리하고 서버에서 전달하는 에러 메시지를 쉽게 확인할 수 있었다