-
Notifications
You must be signed in to change notification settings - Fork 2
NetworkError.swift
JiHyeonJang edited this page Sep 10, 2025
·
2 revisions
NetworkError는 네트워크 요청 과정에서 발생할 수 있는 다양한 오류 상황을 표준화하여 처리하기 위해 만들어진 에러 타입입니다.
이 파일의 목적은 다음과 같습니다.
-
네트워크 오류를 한 곳에서 관리
-
각 오류 상황에 맞는 사용자 안내 메시지 제공
-
디버깅 시 필요한 상세 로그 자동 생성
-
API 서비스, ViewModel, View 어디서든 일관되게 사용 가능
flowchart TD
A[네트워크 요청 시작] --> B{요청 성공 여부?}
B -- 예 --> C[정상 데이터 처리]
B -- 아니오 --> D[오류 발생]
D --> E{오류 원인 확인}
E --> N[NetworkError 케이스 매핑]
E -- URL 형식 오류 --> F[invalidURL]
E -- API 키 문제 --> G[invalidAPIKey]
E -- 서버 응답 없음 --> H[invalidResponse]
E -- 디코딩 실패 --> I[decodingError]
E -- 상태 코드 오류 --> J[notFound / quotaExceeded / serverError]
E -- 기타 --> K[unknown]
N --> L[UI 표시: error.localizedDescription]
N --> M[로그 기록: error.log()]
/// 네트워크 에러를 정의한 객체입니다.
enum NetworkError: Error {
case networkError(_ error: URLError) // 일반 네트워크 오류
case taskCancelled // 작업 취소
case invalidURL // 잘못된 URL
case invalidResponse // 유효하지 않은 응답
case encodingError // 인코딩 오류
case decodingError(_ error: DecodingError) // 디코딩 오류
case invalidAPIKey // API 키 오류
case quotaExceeded(_ statusCode: Int) // 호출 한도 초과
case notFound(_ statusCode: Int) // 리소스 없음
case uriTooLong(_ statusCode: Int) // URI 길이 초과
case serviceUnavilable(_ statusCode: Int) // 서버 점검/장애
case serverError(_ statusCode: Int) // 서버 내부 오류
case remoteError(_ statusCode: Int, _ errorData: String) // 서버 전달 오류
case unknown(_ statusCode: Int) // 알 수 없는 상태 코드
case webSocketError // 웹소켓 오류
}
| 카테고리 | 케이스명 | 설명 |
|---|---|---|
| 일반 네트워크 오류 | networkError(_ error: Error) | 네트워크 연결 실패, 타임아웃 등 |
| 작업 취소 | taskCancelled | 사용자가 요청을 취소 |
| 요청 오류 | invalidURL | 잘못된 URL |
| 응답 오류 | invalidResponse | 서버 응답 형식이 유효하지 않음 |
| 인코딩 오류 | encodingError | 요청 데이터 인코딩 실패 |
| 디코딩 오류 | decodingError(_ error: DecodingError) | 응답 JSON 디코딩 실패 |
| 인증 오류 | invalidAPIKey | API 키 누락/유효하지 않음 |
| 쿼터 초과 (401) | quotaExceeded(_ statusCode: Int) | API 호출 한도 초과 |
| 리소스 없음 (404) | notFound(_ statusCode: Int) | 요청 리소스를 찾을 수 없음 (404) |
| URI 오류 (414) | uriTooLong(_ statusCode: Int) | URI 길이 초과 |
| 서버 점검/장애 (503) | serviceUnavilable(_ statusCode: Int) | 서버가 유지보수 중/일시적 장애 |
| 서버 내부 오류 (500..<600) | serverError(_ statusCode: Int) | 서버 내부 처리 오류 |
| 서버 전달 오류 | remoteError(_ statusCode: Int, _ errorData: String) | 서버가 상태 코드와 오류 메시지 전달 |
| 기타 상태 코드 오류 | unknown(_ statusCode: Int) | 정의되지 않은 상태 코드 |
| 웹소켓 오류 | webSocketError | 웹소켓 통신 중 오류 |
extension NetworkError: LocalizedError {
var errorDescription: String? {
switch self {
case .taskCancelled:
return "작업이 취소되었습니다. 아래 버튼을 눌러 다시 시도해 주세요."
default:
return "데이터를 불러오는 데 실패했어요. 잠시 후 다시 시도해 주세요."
}
}
}-
taskCancelled → 취소된 작업임을 안내
-
기타 → 일반적인 실패 안내 메시지
extension NetworkError {
func log(file: String = #fileID, function: String = #function) -> String {
if case .decodingError(let err) = self {
let message: String
switch err {
case .typeMismatch(_, let context),
.valueNotFound(_, let context),
.keyNotFound(_, let context),
.dataCorrupted(let context):
message = context.debugDescription
@unknown default:
message = "알 수 없는 디코딩 오류입니다."
}
let escaped = message.replacingOccurrences(of: "\"", with: "\\\"")
return "decodingError(\"\(escaped)\")-\"\(file)#\(function)\""
}
return "\(String(describing: self))-\"\(file)#\(function)\""
}
}
-
디버깅이나 UI 업데이트를 위해 error를 받아야 하는 경우, 에러를 throw할 때는 반드시 NetworkError에 정의된 케이스를 사용합니다.
특히 디코딩 에러를 바로 catch 할 때, NetworkError에 구현된 내용을 사용할 때 주의해주세요.
아래 예시처럼 catch 블록에서 처리하면 됩니다.
do {
...
} catch {
guard let ne = error as? NetworkError else { return print(error) }
print(ne.log()) // error 로그 출력
// ne.localizedDescription을 이용한 UI 업데이트 등의 작업
}do {
return try JSONDecoder().decode(T.self, from: jsonData)
} catch let decodingError as DecodingError {
// NetworkError로 변환 후 즉시 로그 출력
let networkError = NetworkError.decodingError(decodingError)
print(networkError.log())
}
decodingError("debugDescription")-"Project/MyService.swift#fetchData"
notFound(404)-"Project/MyService.swift#fetchData"
taskCancelled-"Project/MyService.swift#fetchData"