Closed Fezravien closed 3 years ago
ItemList
: 상품 목록 Item
: 상품 // itemList
struct ItemList: Decodable {
let page: UInt16
let items: [Item]
}
// Item
struct Item: Decodable {
let id: UInt
let title: String
let descriptions: String?
let price: UInt
let currency: String
let stock: UInt
let discountPrice: UInt?
let thumbnails: [String]
let images: [String]?
let registrationDate: Double
enum CodingKeys: String, CodingKey {
case id, title, descriptions, price, currency, stock, thumbnails, images
case discountPrice = "discounted_price"
case registrationDate = "registration_date"
}
}
ItemRegistration
: 상품 등록ItemModification
: 상품 수정 ItemDelete
: 상품 삭제ItemModification
스펠링이 틀린거 수정
multipart/form-data
로 서버에 요청하기 위해 구조체 내에 연산 프로퍼티를 통해 키/값 형식을 반환하는 프로퍼티 구성
MultiPartForm 프로토콜을 채택하여 상품 등록 / 수정을 같은 타입으로
상품 삭제는 JSONEncoder
이므로 Encodable 프로토콜 채택
// 상품등록
struct ItemRegistration: MultiPartForm {
let title: String
let descriptions: String
let price: UInt
let currency: String
let stock: UInt
let discountedPrice: UInt?
let images: [Data]
let password: String
var asDictionary: [String : Any?] {
[
"title": self.title,
"descriptions": self.descriptions,
"price": self.price,
"currency": self.currency,
"stock": self.stock,
"discounted_price": self.discountedPrice,
"images": self.images,
"password": self.password
]
}
}
// 상품 수정
struct ItemModification: MultiPartForm {
let title: String?
let descriptions: String?
let price: UInt?
let currency: String?
let stock: UInt?
let discountedPrice: UInt?
let images: [Data]?
let password: String
var asDictionary: [String : Any?] {
[
"title": self.title,
"descriptions": self.descriptions,
"price": self.price,
"currency": self.currency,
"stock": self.stock,
"discounted_price": self.discountedPrice,
"images": self.images,
"password": self.password
]
}
}
// 상품 삭제
struct ItemDelete: Encodable {
let password: String
}
GET, POST, PATCH, DELETE 오버로딩을 통해 동일한 메소드 명으로 파라미터만 다르게 하여 일관성을 유지했다
/// GET - 목록 조회
func createRequest(page: UInt) -> URLRequest? {
guard let fetchURL = NetworkConstant.itemList(page: page).url else { return nil }
let request = URLRequest(url: fetchURL)
return request
}
/// GET - 상품 조회
func createRequest(id: UInt) -> URLRequest? {
guard let fetchURL = NetworkConstant.item(id: id).url else { return nil }
let request = URLRequest(url: fetchURL)
return request
}
/// DELETE - 상품 삭제 (JSONEncoder)
func createRequest<T: Encodable>(data: T, itemID: UInt) throws -> URLRequest? {
let encodeData: Data
do {
encodeData = try encoder.encode(data)
} catch {
throw MarketModelError.encoding(error)
}
guard let deleteURL = NetworkConstant.delete(id: itemID).url else { return nil }
var request = URLRequest(url: deleteURL)
request.httpMethod = "DELETE"
request.httpBody = encodeData
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
return request
}
/// POST, PATCH - 상품 등록/수정 (mulitpart/form-data)
func createRequest<T: MultiPartForm>(url: URL?, encodeType: T, method: NetworkConstant.Method) throws -> URLRequest {
guard let url = url else { throw MarketModelError.url }
switch method {
case .post:
return createMultipartFormRequest(url: url, type: encodeType, method: .post)
case .patch:
return createMultipartFormRequest(url: url, type: encodeType, method: .patch)
default :
throw MarketModelError.createRequest
}
}
URLSession
외부에서 의존성을 주입받는다.
핸들러는 Result
타입으로 하여
성공 : 데이터
실패 : 특정 오류
오케이
final class Network: MarketNetwork {
private let session: MarketSession
init(session: MarketSession) {
self.session = session
}
func excuteNetwork(request: URLRequest, completion: @escaping (Result<Data?, Error>) -> Void) {
session.dataTask(with: request) { data, response, error in
if let _ = error {
completion(.failure(MarketModelError.network))
return
}
guard let response = response as? HTTPURLResponse else {
completion(.failure(MarketModelError.casting("HTTPURLResponse")))
return
}
guard (200...299) ~= response.statusCode else {
completion(.failure(MarketModelError.response(response.statusCode)))
return
}
completion(.success(data))
}.resume()
}
}
모델 리펙토링 및 개선하기
모델
Response
: 서버로부터 응답받은 데이터 파싱 모델Request
: 서버로 요청하기 위한 모델 (JSONEncoder, multipart/form-data)Network
: 서버에 네트워크 요청 및 응답NetworkManager
: 서버 네트워크를 핸들링 (request, response, fetch ... )리펙토링 및 개선할 부분 및 생각해볼 부분
Response
Request
NetworkManager
Network