팀원과 페어 프로그래밍으로 네트워크 레이어의 기반을 설계했습니다.
HttpMethod 열거형
enum HttpMethod: String {
case get = "GET"
case post = "POST"
case put = "PUT"
case delete = "DELETE"
}
Requestable 프로토콜
protocol Requestable {
associatedtype Response: Decodable
var baseURL: String { get }
var httpMethod: HttpMethod { get }
var path: String { get }
var queryItems: [URLQueryItem] { get }
var headers: [String: String] { get }
func makeURLRequest() -> URLRequest?
}
NetworkError 열거형
enum NetworkError: Error {
case invalidURL
case urlSessionFailed(Error)
case invalidResponse
case serverError(code: ServerErrorCode, message: String?)
case emptyData
case encodingFailed(Error)
case decodingFailed(Error)
case unknown(Error?)
}
빠른 기능 구현을 위해 URLSession을 직접 사용하는 방식을 선택했습니다.
LoginManager 구현
final class LoginManager {
static let shared = LoginManager()
private init() {}
func login(username: String, password: String, completion: @escaping (Result<Token, Error>) -> Void) {
// 1. URLRequest 생성 (하드코딩)
let url = URL(string: "<https://popcorn.store/login>")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// 2. JSON 요청 바디 생성
let requestBody: [String: String] = [
"username": username,
"password": password
]
request.httpBody = try? JSONSerialization.data(withJSONObject: requestBody)
// 3. URLSession 요청
let task = URLSession.shared.dataTask(with: request) { data, response, error in
// 4. 에러 처리
if let error = error {
completion(.failure(error))
return
}
// 5. HTTP 응답 검증
guard let httpResponse = response as? HTTPURLResponse,
let data = data else {
completion(.failure(NSError(domain: "InvalidResponse", code: -1)))
return
}
// 6. 상태 코드 검증
if httpResponse.statusCode == 200 {
// 7. JSON 디코딩
do {
let loginResponse = try JSONDecoder().decode(LoginResponse.self, from: data)
completion(.success(loginResponse.data))
} catch {
completion(.failure(error))
}
} else {
completion(.failure(NSError(domain: "LoginFailed", code: httpResponse.statusCode)))
}
}
task.resume()
}
}
하드코딩 방식의 문제점