Skip to content

Commit

Permalink
🔀 상품 개수 API 연결 (#33)
Browse files Browse the repository at this point in the history
* ✨ Implement product count api request model and endpoint

* 🚧 Create mock JSON and response model

- Connected URLProtocol with mock JSON and linked the network flow in `HomeService`, setting up a foundation for network testing.

* 🐛 Fix bug where mock JSON file could not be read

* ✨ Connect HomeProductCount API to view
  • Loading branch information
WhiteHyun authored Feb 3, 2024
1 parent 0558b45 commit 1240c2d
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 32 deletions.
2 changes: 1 addition & 1 deletion APIService/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ let package = Package(
dependencies: [
"HomeAPI",
],
resources: [.process("HomeProductResponse.json")]
resources: [.process("Mocks")]
),
]
)
37 changes: 32 additions & 5 deletions APIService/Sources/HomeAPI/HomeEndPoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,39 @@
import Foundation
import Network

struct HomeEndPoint: EndPoint {
let method: HTTPMethod = .get
// MARK: - HomeEndPoint

let path: String = "v2/products"
public enum HomeEndPoint {
case fetchProducts(ProductRequest)
case fetchCount(ProductCountRequest)
}

// MARK: EndPoint

extension HomeEndPoint: EndPoint {
public var method: HTTPMethod {
.get
}

public var path: String {
switch self {
case .fetchProducts:
"/v2/products"
case .fetchCount:
"/v2/products/count"
}
}

let parameters: HTTPParameter = .plain
public var parameters: HTTPParameter {
switch self {
case let .fetchProducts(requestModel):
.query(requestModel)
case let .fetchCount(requestModel):
.query(requestModel)
}
}

let headers: [String: String] = ["Content-Type": "application/json"]
public var headers: [String: String] {
["Content-Type": "application/json"]
}
}
12 changes: 9 additions & 3 deletions APIService/Sources/HomeAPI/HomeService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import Network
// MARK: - HomeServiceRepresentable

public protocol HomeServiceRepresentable {
func fetchProductList() async throws -> [Product]
func fetchProductList(request: ProductRequest) async throws -> [Product]
func fetchProductCount(request: ProductCountRequest) async throws -> Int
}

// MARK: - HomeService
Expand All @@ -28,10 +29,15 @@ public struct HomeService {
// MARK: HomeServiceRepresentable

extension HomeService: HomeServiceRepresentable {
public func fetchProductList() async throws -> [Product] {
let products: [ProductResponse] = try await network.request(with: HomeEndPoint())
public func fetchProductList(request: ProductRequest) async throws -> [Product] {
let products: [ProductResponse] = try await network.request(with: HomeEndPoint.fetchProducts(request))
return products.map(Product.init)
}

public func fetchProductCount(request: ProductCountRequest) async throws -> Int {
let countResponse: ProductCountResponse = try await network.request(with: HomeEndPoint.fetchCount(request))
return countResponse.count
}
}

private extension Product {
Expand Down
17 changes: 17 additions & 0 deletions APIService/Sources/HomeAPI/Requests/ProductCountRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// ProductCountRequest.swift
//
//
// Created by 홍승현 on 2/2/24.
//

import Entity
import Foundation

public struct ProductCountRequest: Encodable {
public let convenienceStore: ConvenienceStore

public init(convenienceStore: ConvenienceStore) {
self.convenienceStore = convenienceStore
}
}
8 changes: 8 additions & 0 deletions APIService/Sources/HomeAPI/Requests/ProductRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@ public struct ProductRequest: Encodable {
public let order: Order
public let pageSize: Int
public let offset: Int

public init(store: ConvenienceStore, promotion: Promotion, order: Order, pageSize: Int, offset: Int) {
self.store = store
self.promotion = promotion
self.order = order
self.pageSize = pageSize
self.offset = offset
}
}
12 changes: 12 additions & 0 deletions APIService/Sources/HomeAPI/Responses/ProductCountResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// ProductCountResponse.swift
//
//
// Created by 홍승현 on 2/2/24.
//

import Foundation

struct ProductCountResponse: Decodable {
let count: Int
}
16 changes: 8 additions & 8 deletions APIService/Sources/HomeAPI/Responses/ProductResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
import Entity
import Foundation

public struct ProductResponse: Decodable {
public let id: Int
public let imageURL: URL
public let price: Int
public let name: String
public let promotion: Promotion
public let convenienceStore: ConvenienceStore
struct ProductResponse: Decodable {
let id: Int
let imageURL: URL
let price: Int
let name: String
let promotion: Promotion
let convenienceStore: ConvenienceStore

public enum CodingKeys: String, CodingKey {
enum CodingKeys: String, CodingKey {
case id
case imageURL = "image_url"
case price
Expand Down
15 changes: 12 additions & 3 deletions APIService/Sources/HomeAPISupport/HomeURLProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@
//

import Foundation
import HomeAPI
import Network

public final class HomeURLProtocol: URLProtocol {
private let fileName = "HomeProductResponse"
private lazy var mockData: [String: Data?] = [
HomeEndPoint.fetchProducts(
.init(store: .gs25, promotion: .allItems, order: .normal, pageSize: 0, offset: 0)
).path: loadMockData(fileName: "HomeProductResponse"),
HomeEndPoint.fetchCount(
.init(convenienceStore: .gs25)
).path: loadMockData(fileName: "HomeProductCountResponse"),
]

override public class func canInit(with _: URLRequest) -> Bool {
true
Expand All @@ -21,8 +29,9 @@ public final class HomeURLProtocol: URLProtocol {

override public func startLoading() {
defer { client?.urlProtocolDidFinishLoading(self) }
if let data = loadMockData(fileName: fileName),
let url = request.url,
if let url = request.url,
let mockData = mockData[url.path(percentEncoded: true)],
let data = mockData,
let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil) {
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
client?.urlProtocol(self, didLoad: data)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"count": 24
}
1 change: 0 additions & 1 deletion Core/Sources/Network/NetworkProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Created by 홍승현 on 1/25/24.
//

import Combine
import Foundation

// MARK: - NetworkProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@
import SwiftUI

struct HomeProductSorterView: View {
private let count: Int

init(count: Int) {
self.count = count
}
@EnvironmentObject private var viewModel: HomeViewModel
@State private var count: Int = 0

var body: some View {
HStack {
Expand All @@ -24,6 +21,11 @@ struct HomeProductSorterView: View {
}
}
.padding(.all, 8)
.onAppear {
Task {
count = try await viewModel.fetchProductCounts()
}
}
}

var productCountString: AttributedString {
Expand All @@ -36,7 +38,3 @@ struct HomeProductSorterView: View {
return string
}
}

#Preview {
HomeProductSorterView(count: 50)
}
2 changes: 1 addition & 1 deletion PyeonHaeng-iOS/Sources/Scenes/HomeScene/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct HomeView: View {
NavigationStack {
VStack {
HomeProductDetailSelectionView()
HomeProductSorterView(count: 12)
HomeProductSorterView()
HomeProductListView()
}
.padding(.horizontal, Metrics.horizontal)
Expand Down
15 changes: 14 additions & 1 deletion PyeonHaeng-iOS/Sources/Scenes/HomeScene/HomeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ final class HomeViewModel: ObservableObject {
}

func fetchProducts() async throws {
try await products.append(contentsOf: service.fetchProductList())
// TODO: View와 연결할 때 수정해야합니다.
let request: ProductRequest = .init(
store: .gs25,
promotion: .buyOneGetOneFree,
order: .normal,
pageSize: 20,
offset: 0
)
try await products.append(contentsOf: service.fetchProductList(request: request))
}

func fetchProductCounts() async throws -> Int {
// TODO: 편의점 선택 뷰를 구성할 때 수정해야합니다.
try await service.fetchProductCount(request: .init(convenienceStore: .gs25))
}
}

0 comments on commit 1240c2d

Please sign in to comment.