-
Notifications
You must be signed in to change notification settings - Fork 0
Feat/#100 마이페이지 API 연결 #120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "feat#100-\uB9C8\uC774\uD398\uC774\uC9C0-api"
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| // | ||
| // UserInfoResponseDTO.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 이나연 on 1/20/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| struct UserInfoResponseDTO: Decodable { | ||
| let name: String | ||
| let daysSinceSignup: Int | ||
| } | ||
|
|
||
| extension UserInfoResponseDTO { | ||
| func toEntity() -> UserInfoEntity { | ||
| .init(name: name, daysSinceSignup: daysSinceSignup) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| // | ||
| // MyPageAPI.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 이나연 on 1/20/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| import Alamofire | ||
|
|
||
| enum MyPageAPI { | ||
| case users(userID: Int) | ||
| } | ||
|
|
||
| extension MyPageAPI: EndPoint { | ||
| var basePath: String { | ||
| return "/api" | ||
| } | ||
|
|
||
| var path: String { | ||
| switch self { | ||
| case .users: | ||
| return "/users" | ||
| } | ||
| } | ||
|
|
||
| var method: Alamofire.HTTPMethod { | ||
| switch self { | ||
| case .users: | ||
| return .get | ||
| } | ||
| } | ||
|
|
||
| var headers: HeaderType { | ||
| switch self { | ||
| case .users(let userID): | ||
| return .withAuth(userID: userID) | ||
| } | ||
| } | ||
|
|
||
| var parameterEncoding: any Alamofire.ParameterEncoding { | ||
| switch self { | ||
| case .users: | ||
| return URLEncoding.default | ||
| } | ||
| } | ||
|
|
||
| var queryParameters: [String : Any]? { | ||
| return nil | ||
| } | ||
|
|
||
| var bodyParameters: Alamofire.Parameters? { | ||
| return nil | ||
| } | ||
|
|
||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| // | ||
| // MyPageRepository.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 이나연 on 1/20/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| struct DefaultMyPageRepository: MyPageInterface { | ||
| private let networkService: NetworkService | ||
| private let userDefaultService: UserDefaultService | ||
|
|
||
| init( | ||
| networkService: NetworkService, | ||
| userDefaultService: UserDefaultService | ||
| ) { | ||
| self.networkService = networkService | ||
| self.userDefaultService = userDefaultService | ||
| } | ||
|
|
||
| func fetchUserInfo() async throws -> UserInfoEntity { | ||
| let userID: Int = userDefaultService.load(key: .userID) ?? 1 | ||
| let response = try await networkService.request( | ||
| MyPageAPI.users(userID: userID), | ||
| decodingType: UserInfoResponseDTO.self) | ||
|
|
||
| return response.toEntity() | ||
|
Comment on lines
+22
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. userID 기본값 1은 타 사용자 정보 노출 위험. Line 23에서 🔧 권장 수정안 func fetchUserInfo() async throws -> UserInfoEntity {
- let userID: Int = userDefaultService.load(key: .userID) ?? 1
+ guard let userID: Int = userDefaultService.load(key: .userID) else {
+ throw MyPageRepositoryError.missingUserID
+ }
let response = try await networkService.request(
MyPageAPI.users(userID: userID),
decodingType: UserInfoResponseDTO.self)
return response.toEntity()
}
+
+enum MyPageRepositoryError: Error {
+ case missingUserID
+}🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // | ||
| // MyPageInterface.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 이나연 on 1/20/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| protocol MyPageInterface { | ||
| func fetchUserInfo() async throws -> UserInfoEntity | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // | ||
| // UserInfoEntity.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 이나연 on 1/20/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| struct UserInfoEntity { | ||
| let name: String | ||
| let daysSinceSignup: Int | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| // | ||
| // FetchUserInfoUseCase.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 이나연 on 1/20/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| protocol FetchUserInfoUseCase { | ||
| func execute() async throws -> UserInfoEntity | ||
| } | ||
|
|
||
| struct DefaultFetchUserInfoUserCase: FetchUserInfoUseCase { | ||
| private let repository: MyPageInterface | ||
|
|
||
| init(repository: MyPageInterface) { | ||
| self.repository = repository | ||
| } | ||
|
|
||
| func execute() async throws -> UserInfoEntity { | ||
| return try await repository.fetchUserInfo() | ||
|
Comment on lines
+14
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 타입명 오타(UserCase) 정리 권장. Line 14의 ♻️ 권장 수정안-struct DefaultFetchUserInfoUserCase: FetchUserInfoUseCase {
+struct DefaultFetchUserInfoUseCase: FetchUserInfoUseCase {🤖 Prompt for AI Agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요고 확인 부탁드릴게욤 |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,8 @@ | |
| import SwiftUI | ||
|
|
||
| struct MyPageView: View { | ||
| @StateObject var viewModel: MyPageViewModel | ||
|
|
||
|
Comment on lines
+11
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 주입된 뷰모델은 Line 11-12의 ♻️ 권장 수정안- `@StateObject` var viewModel: MyPageViewModel
+ `@ObservedObject` var viewModel: MyPageViewModel또는 `@StateObject` private var viewModel: MyPageViewModel
init(viewModel: MyPageViewModel) {
_viewModel = StateObject(wrappedValue: viewModel)
}🤖 Prompt for AI Agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요 방법이 맞는 거 같기는 한데 한번 확인 부탁드려요! |
||
| var body: some View { | ||
| VStack { | ||
| Spacer() | ||
|
|
@@ -18,6 +20,13 @@ struct MyPageView: View { | |
| .padding(.horizontal, 35) | ||
| grayEmptyBar | ||
| } | ||
| .task { | ||
| do { | ||
| try await viewModel.fetchUserInfo() | ||
| } catch { | ||
| CherrishLogger.error(error) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -29,10 +38,10 @@ extension MyPageView { | |
| .frame(width: 48.adjustedW, height: 48.adjustedH) | ||
|
|
||
| VStack(alignment: .leading, spacing: 0){ | ||
| TypographyText("안녕하세요, 김채채 님", style: .title1_sb_18, color: .gray1000) | ||
| TypographyText("안녕하세요, \(viewModel.name)님", style: .title1_sb_18, color: .gray1000) | ||
| .frame(height: 27.adjustedH) | ||
|
|
||
| TypographyText("관리 시작 D + 13", style: .body1_m_14, color: .gray800) | ||
| TypographyText("관리 시작 D + \(viewModel.day)", style: .body1_m_14, color: .gray800) | ||
| .frame(height: 20.adjustedH) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // | ||
| // MyPageViewModel.swift | ||
| // Cherrish-iOS | ||
| // | ||
| // Created by 이나연 on 1/20/26. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| final class MyPageViewModel: ObservableObject { | ||
| @Published private(set) var name: String = "" | ||
| @Published private(set) var day: Int = 1 | ||
|
|
||
| private let fetchUserInfoUseCase: FetchUserInfoUseCase | ||
|
|
||
| init(fetchUserInfoUseCase: FetchUserInfoUseCase) { | ||
| self.fetchUserInfoUseCase = fetchUserInfoUseCase | ||
| } | ||
|
|
||
| @MainActor | ||
| func fetchUserInfo() async throws { | ||
| let response = try await fetchUserInfoUseCase.execute() | ||
| name = response.name | ||
| day = response.daysSinceSignup | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -71,5 +71,13 @@ final class PresentationDependencyAssembler: DependencyAssembler { | |||||||||||||||||||||||||||||||
| DIContainer.shared.register(type: TreatmentViewModel.self) { | ||||||||||||||||||||||||||||||||
| return TreatmentViewModel(fetchTreatmentsUseCase: fetchTreatmentsUseCase) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| guard let fetchUserInfoUseCase = DIContainer.shared.resolve(type: FetchUserInfoUseCase.self) else { | ||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| DIContainer.shared.register(type: MyPageViewModel.self) { | ||||||||||||||||||||||||||||||||
| return MyPageViewModel(fetchUserInfoUseCase: fetchUserInfoUseCase) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
Comment on lines
+75
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DI 실패 로그 누락으로 원인 추적이 어려움
🛠️ 제안 수정안- guard let fetchUserInfoUseCase = DIContainer.shared.resolve(type: FetchUserInfoUseCase.self) else {
- return
- }
+ guard let fetchUserInfoUseCase = DIContainer.shared.resolve(type: FetchUserInfoUseCase.self) else {
+ CherrishLogger.error(CherrishError.DIFailedError)
+ return
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 134
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 266
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 52
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 2597
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 52
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 52
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 52
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 52
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 52
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 52
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 1194
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 199
🏁 Script executed:
# Look at MyPageRepository more carefully cat ./Cherrish-iOS/Cherrish-iOS/Data/Repository/MyPageRepository.swiftRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 877
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 5072
🏁 Script executed:
Repository: TEAM-Cherrish/Cherrish-iOS
Length of output: 133
🏁 Script executed:
# Examine MyPageAPI.swift cat ./Cherrish-iOS/Cherrish-iOS/Data/Network/EndPoint/MyPageAPI.swiftRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 1039
🏁 Script executed:
# Examine NetworkService.swift cat ./Cherrish-iOS/Cherrish-iOS/Data/Network/NetworkService.swiftRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 4441
🏁 Script executed:
# Check the single test file to see if there are response examples cat ./Cherrish-iOS/Cherrish-iOS/Data/Network/EndPoint/TestAPI.swiftRepository: TEAM-Cherrish/Cherrish-iOS
Length of output: 269
API 응답 키 형식과의 매핑이 명시되지 않아 디코딩 실패 위험.
daysSinceSignup은 서버 응답이 snake_case 형식(예:days_since_signup)일 경우 디코딩에 실패합니다. NetworkService에서JSONDecoder()를 기본 설정으로 사용하고 있어서 키명이 정확히 일치해야 하는데, 실제 API 응답 형식이 코드에 명시되지 않았습니다.CodingKeys를 추가하거나keyDecodingStrategy를 설정하여 안전하게 처리해주세요.수정안
struct UserInfoResponseDTO: Decodable { let name: String let daysSinceSignup: Int + + private enum CodingKeys: String, CodingKey { + case name + case daysSinceSignup = "days_since_signup" + } }📝 Committable suggestion
🤖 Prompt for AI Agents