코드네임 :
Swift - Moya사용하기 본문
// Request
//
// CardInfo.swift
// EatPic-iOS
//
// Created by 이은정 on 8/9/25.
//
// Codable 객체
struct CreateCardRequest: Codable {
let meal: String
let memo: String
let recipe: String
let location: CreateCardRequestLocation
let isShared: Bool
let recipeUrl: String?
let cardImageUrl: String?
let hashtag: [CreateCardRequestHashtag]
enum CodingKeys: String, CodingKey {
case meal, memo, recipe, location, hashtag
case isShared = "is_shared"
case recipeUrl = "recipe_url"
case cardImageUrl = "card_image_url"
}
}
struct CreateCardRequestLocation: Codable {
let name: String
let latitude: Double
let longitude: Double
}
struct CreateCardRequestHashtag: Codable {
let hashtagId: String
let hashtagName: String
enum CodingKeys: String, CodingKey {
case hashtagId
case hashtagName = "hashtag_name"
}
}
//Response
import Foundation
struct CardDetailResponse: Codable {
let isSuccess: Bool
let code: String
let message: String
let result: CardDetailResponseResult
}
struct CardDetailResponseResult: Codable {
let cardId: Int
let imageUrl: String
let date: String
let time: String
let mealType: String
let recipeUrl: String
let latitude: Double
let longitude: Double
let locationText: String
let memo: String
let recipe: String
let nextMeal: NextMeal
enum CodingKeys: String, CodingKey {
case cardId
case imageUrl
case date
case time
case mealType
case recipeUrl
case latitude
case longitude
case locationText
case memo
case recipe
case nextMeal
}
}
struct NextMeal: Codable {
let cardId: Int
}
//
// CreateCardResponse.swift
// EatPic-iOS
//
// Created by 이은정 on 8/9/25.
//
struct CreateCardResponse: Codable {
let isSuccess: Bool
let code: String
let message: String
let result: CreateCardResponseResult
}
struct CreateCardResponseResult: Codable {
let meal: String
let memo: String
let recipe: String
let location: CreateCardResponseLocation
let isShared: Bool
let recipeUrl: String?
let cardImageUrl: String?
let hashtag: [CreateCardResponseHashtag]
enum CodingKeys: String, CodingKey {
case meal, memo, recipe, location, hashtag
case isShared = "is_shared"
case recipeUrl = "recipe_url"
case cardImageUrl = "card_image_url"
}
}
struct CreateCardResponseLocation: Codable {
let name: String
let latitude: Double
let longitude: Double
}
struct CreateCardResponseHashtag: Codable {
let hashtagId: String
let hashtagName: String
enum CodingKeys: String, CodingKey {
case hashtagId
case hashtagName = "hashtag_name"
}
}
// TargetType
//
// CardTargetType.swift
// EatPic-iOS
//
// Created by 이은정 on 8/9/25.
//
import Foundation
import Moya
enum CardTargetType {
case createCard(request: CreateCardRequest)
case fetchCardDetail(cardId: Int)
}
extension CardTargetType: APITargetType {
var path: String {
switch self {
case .createCard:
return "/newcard"
case .fetchCardDetail(let cardId):
return "/api/cards/{cardId}"
}
}
var method: Moya.Method {
switch self {
case .createCard:
return .post
case .fetchCardDetail:
return .get
}
}
var task: Moya.Task {
switch self {
case .createCard(let request):
return .requestJSONEncodable(request)
case .fetchCardDetail:
return .requestPlain
}
}
var sampleData: Data {
switch self {
case .createCard:
return Data("""
{
"isSuccess": true,
"code": "COMMON_201",
"message": "Pic 카드가 기록되었습니다.",
"result": {
"meal": "dinner",
"memo": "어쩌구저쩌구",
"recipe": "레시피 내용",
"location": {
"name": "서울 강남구",
"latitude": 37.4979,
"longitude": 127.0276
},
"is_shared": true,
"recipe_url": "http://...",
"card_image_url": "image.png",
"hashtag": [
{ "hashtagId": "1", "hashtag_name": "한식" },
{ "hashtagId": "2", "hashtag_name": "양식" },
{ "hashtagId": "3", "hashtag_name": "중식" }
]
}
}
""".utf8)
case .fetchCardDetail:
return Data("""
{
"isSuccess": true,
"code": "string",
"message": "string",
"result": {
"cardId": 1,
"imageUrl": "https://cdn.eatpic.com/cards/123.jpg",
"date": "2025-07-01",
"time": "10:10",
"mealType": "BREAKFAST",
"recipeUrl": "https://recipe.example.com/salad-abc123",
"latitude": 37.4979,
"longitude": 127.0276,
"locationText": "장소 이름",
"memo": "오늘은 샐러드를 먹었습니다~ 아보카도를 많이 넣어 먹었어요~~",
"recipe": "이 레시피는요 일단 야채들이 필요하고요...",
"nextMeal": {
"cardId": 2
}
}
}
""".utf8)
}
}
}
// APIProviderStore
//
// APIProviderStore.swift
// EatPic-iOSTests
//
// Created by jaewon Lee on 7/19/25.
//
import Foundation
import Moya
/// APIProviderStore는 각 도메인별로 필요한 MoyaProvider를 생성하는 책임을 갖습니다.
/// 네트워크 서비스에 의존하여 필요한 프로바이더를 외부에 제공합니다.
final class APIProviderStore {
let networkService: NetworkService
init(networkService: NetworkService) {
self.networkService = networkService
}
}
extension APIProviderStore {
/// 사용자 API 요청을 위한 MoyaProvider를 반환합니다.
/// 기본적으로 테스트용 Provider를 반환하도록 구성되어 있습니다.
/// 추후, 실제 프로바이더로 변경해야 합니다.
func user() -> MoyaProvider<UserTargetType> {
return networkService.testProvider(for: UserTargetType.self)
}
func card() -> MoyaProvider<CardTargetType> {
return networkService.testProvider(for: CardTargetType.self)
}
func cardDetail() -> MoyaProvider<CardTargetType> {
return networkService.testProvider(for: CardTargetType.self)
}
}
// ViewModel
//
// CardViewModel.swift
// EatPic-iOS
//
// Created by 이은정 on 8/10/25.
//
import Foundation
import Moya
struct CardModel {
let profileImageUrl: String
let id: Int
let time: String
let imageURL: String
let recipeUrl: String
let latitude: Double
let longitude: Double
let locationText: String
let memo: String
let recipe: String
}
@Observable
final class CardViewModel {
private let cardProvider: MoyaProvider<CardTargetType>
init(container: DIContainer) {
self.cardProvider = container.apiProviderStore.cardDetail()
}
@MainActor
func fetchCardDetail(cardId: Int) async {
do {
let response = try await cardProvider.requestAsync(.fetchCardDetail(cardId: cardId))
let dto = try JSONDecoder().decode(CardDetailResponse.self, from: response.data)
print(dto)
} catch {
print("요청 또는 디코딩 실패:", error.localizedDescription)
}
}
}
// View
//
// CardTestView.swift
// EatPic-iOS
//
// Created by 이은정 on 8/10/25.
//
import SwiftUI
struct CardTestView: View {
@State private var viewModel = CardViewModel(container: .init())
var body: some View {
VStack(spacing: 16) {
Button("카드 상세 조회") {
Task {
await viewModel.fetchCardDetail(cardId: 1)
}
}
}
}
}
#Preview {
CardTestView()
}
'👥Club > 🍀UMC🍀' 카테고리의 다른 글
Git (0) | 2025.07.07 |
---|---|
Github-flow (1) | 2025.07.07 |
🍎 iOS 1주차 과제 (0) | 2025.07.03 |
🍎 Alamofire (0) | 2025.05.29 |
🍎 Combine (0) | 2025.05.28 |