diff --git a/GAMSS/Sources/Core/Network/Endpoint.swift b/GAMSS/Sources/Core/Network/Endpoint.swift deleted file mode 100644 index 239976f..0000000 --- a/GAMSS/Sources/Core/Network/Endpoint.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// Endpoint.swift -// GAMSS -// -// Created by 이건준 on 7/19/26. -// - -import Foundation - -protocol Endpoint { - var baseURLString: String { get } - var path: String { get } - var method: HTTPMethod { get } - var body: Encodable? { get } -} - -extension Endpoint { - var baseURLString: String { - return Environment.baseURL - } - - var headers: [String: String] { - return [ - "Content-Type": "application/json", - "Accept": "application/json" - ] - } - - func asURLRequest() throws -> URLRequest { - guard let url = URL( - string: "\(baseURLString)\(path)" - ) else { - throw NetworkError.invalidURL - } - - var request = URLRequest(url: url) - request.httpMethod = method.rawValue - - headers.forEach { - request.setValue( - $1, - forHTTPHeaderField: $0 - ) - } - - if let body { - request.httpBody = try JSONEncoder().encode(body) - } - - return request - } -} - -enum HTTPMethod: String { - case get = "GET" - case post = "POST" - case put = "PUT" - case patch = "PATCH" - case delete = "DELETE" -} diff --git a/GAMSS/Sources/Core/Network/Foundation/Endpoint.swift b/GAMSS/Sources/Core/Network/Foundation/Endpoint.swift new file mode 100644 index 0000000..274fda2 --- /dev/null +++ b/GAMSS/Sources/Core/Network/Foundation/Endpoint.swift @@ -0,0 +1,64 @@ +// +// Endpoint.swift +// GAMSS +// +// Created by 이건준 on 7/19/26. +// + +import Foundation + +protocol Endpoint { + var baseURLString: String { get } + var path: String { get } + var method: HTTPMethod { get } + var parameters: [RequestParameter] { get } + var header: HTTPHeader { get } +} + +extension Endpoint { + var baseURLString: String { + return Environment.baseURL + } + + func asURLRequest() throws -> URLRequest { + guard var components = URLComponents( + string: "\(baseURLString)\(path)" + ) else { + throw NetworkError.invalidURL + } + + var httpBody: Data? + + for parameter in parameters { + switch parameter { + case let .query(query): + components.queryItems = (components.queryItems ?? []) + query.map { + URLQueryItem( + name: $0.key, + value: $0.value + ) + } + + case let .body(body): + httpBody = try JSONEncoder().encode(body) + } + } + + guard let url = components.url else { + throw NetworkError.invalidURL + } + + var request = URLRequest(url: url) + request.httpMethod = method.rawValue + request.httpBody = httpBody + + header.fields.forEach { + request.setValue( + $1, + forHTTPHeaderField: $0 + ) + } + + return request + } +} diff --git a/GAMSS/Sources/Core/Network/Foundation/HttpHeader.swift b/GAMSS/Sources/Core/Network/Foundation/HttpHeader.swift new file mode 100644 index 0000000..2fca924 --- /dev/null +++ b/GAMSS/Sources/Core/Network/Foundation/HttpHeader.swift @@ -0,0 +1,40 @@ +// +// HttpHeader.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +enum HTTPHeader { + case `default` + case authorization + case custom([String: String]) + + private var commonFields: [String: String] { + [ + "Content-Type": "application/json", + "Accept": "application/json" + ] + } + + var fields: [String: String] { + switch self { + case .default: + return commonFields + + case .authorization: + var fields = commonFields + + if let accessToken = TokenStorage.shared.readToken(.accessToken) { + fields["Authorization"] = "Bearer \(accessToken)" + } + + return fields + + case let .custom(headers): + return headers + } + } +} diff --git a/GAMSS/Sources/Core/Network/Foundation/HttpMethod.swift b/GAMSS/Sources/Core/Network/Foundation/HttpMethod.swift new file mode 100644 index 0000000..aa8dcb4 --- /dev/null +++ b/GAMSS/Sources/Core/Network/Foundation/HttpMethod.swift @@ -0,0 +1,16 @@ +// +// HttpMethod.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +enum HTTPMethod: String { + case get = "GET" + case post = "POST" + case put = "PUT" + case patch = "PATCH" + case delete = "DELETE" +} diff --git a/GAMSS/Sources/Core/Network/Foundation/RequestParameter.swift b/GAMSS/Sources/Core/Network/Foundation/RequestParameter.swift new file mode 100644 index 0000000..4410aea --- /dev/null +++ b/GAMSS/Sources/Core/Network/Foundation/RequestParameter.swift @@ -0,0 +1,13 @@ +// +// RequestParameter.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +enum RequestParameter { + case query([String: String]) + case body(Encodable) +} diff --git a/GAMSS/Sources/Data/DTO/LoginRequestDTO.swift b/GAMSS/Sources/Data/DTO/Auth/Request/LoginRequestDTO.swift similarity index 100% rename from GAMSS/Sources/Data/DTO/LoginRequestDTO.swift rename to GAMSS/Sources/Data/DTO/Auth/Request/LoginRequestDTO.swift diff --git a/GAMSS/Sources/Data/DTO/Auth/Request/ReissueTokenRequestDTO.swift b/GAMSS/Sources/Data/DTO/Auth/Request/ReissueTokenRequestDTO.swift new file mode 100644 index 0000000..2ede1e5 --- /dev/null +++ b/GAMSS/Sources/Data/DTO/Auth/Request/ReissueTokenRequestDTO.swift @@ -0,0 +1,12 @@ +// +// ReissueTokenRequestDTO.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +struct ReissueTokenRequestDTO: Encodable { + let refreshToken: String +} diff --git a/GAMSS/Sources/Data/DTO/LoginResponseDTO.swift b/GAMSS/Sources/Data/DTO/Auth/Response/LoginResponseDTO.swift similarity index 100% rename from GAMSS/Sources/Data/DTO/LoginResponseDTO.swift rename to GAMSS/Sources/Data/DTO/Auth/Response/LoginResponseDTO.swift diff --git a/GAMSS/Sources/Data/DTO/Card/Request/CreateCardRequestDTO.swift b/GAMSS/Sources/Data/DTO/Card/Request/CreateCardRequestDTO.swift new file mode 100644 index 0000000..1b4319a --- /dev/null +++ b/GAMSS/Sources/Data/DTO/Card/Request/CreateCardRequestDTO.swift @@ -0,0 +1,14 @@ +// +// CreateCardsRequestDTO.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +struct CreateCardRequestDTO: Encodable { + let conversationId: Int + let emotion: String + let summary: String +} diff --git a/GAMSS/Sources/Data/DTO/Chat/Request/CreateCommentRequestDTO.swift b/GAMSS/Sources/Data/DTO/Chat/Request/CreateCommentRequestDTO.swift new file mode 100644 index 0000000..b176a38 --- /dev/null +++ b/GAMSS/Sources/Data/DTO/Chat/Request/CreateCommentRequestDTO.swift @@ -0,0 +1,13 @@ +// +// CreateCommentRequestDTO.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +struct CreateCommentRequestDTO: Encodable { + let messageId: Int + let currentConversationSummary: String +} diff --git a/GAMSS/Sources/Data/DTO/Chat/Request/CreateMessageRequestDTO.swift b/GAMSS/Sources/Data/DTO/Chat/Request/CreateMessageRequestDTO.swift new file mode 100644 index 0000000..8f821e5 --- /dev/null +++ b/GAMSS/Sources/Data/DTO/Chat/Request/CreateMessageRequestDTO.swift @@ -0,0 +1,16 @@ +// +// CreateMessageRequestDTO.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +struct CreateMessageRequestDTO: Encodable { + let conversationId: Int + let content: String + let repliesMessageId: Int + let currentConversationSummary: String + let excludeCharacters: [String] +} diff --git a/GAMSS/Sources/Data/DTO/Chat/Request/UpdateChatTitleRequestDTO.swift b/GAMSS/Sources/Data/DTO/Chat/Request/UpdateChatTitleRequestDTO.swift new file mode 100644 index 0000000..b4dda5b --- /dev/null +++ b/GAMSS/Sources/Data/DTO/Chat/Request/UpdateChatTitleRequestDTO.swift @@ -0,0 +1,12 @@ +// +// UpdateChatTitleRequestDTO.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +struct UpdateChatTitleRequestDTO: Encodable { + let title: String +} diff --git a/GAMSS/Sources/Data/DTO/APIResponse.swift b/GAMSS/Sources/Data/DTO/Common/APIResponse.swift similarity index 100% rename from GAMSS/Sources/Data/DTO/APIResponse.swift rename to GAMSS/Sources/Data/DTO/Common/APIResponse.swift diff --git a/GAMSS/Sources/Data/DTO/EmptyResponseDTO.swift b/GAMSS/Sources/Data/DTO/Common/EmptyResponseDTO.swift similarity index 100% rename from GAMSS/Sources/Data/DTO/EmptyResponseDTO.swift rename to GAMSS/Sources/Data/DTO/Common/EmptyResponseDTO.swift diff --git a/GAMSS/Sources/Data/DTO/Member/Request/UpdateNicknameRequestDTO.swift b/GAMSS/Sources/Data/DTO/Member/Request/UpdateNicknameRequestDTO.swift new file mode 100644 index 0000000..ac56960 --- /dev/null +++ b/GAMSS/Sources/Data/DTO/Member/Request/UpdateNicknameRequestDTO.swift @@ -0,0 +1,12 @@ +// +// UpdateNicknameRequestDTO.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +struct UpdateNicknameRequestDTO: Encodable { + let nickname: String +} diff --git a/GAMSS/Sources/Data/Endpoint/AuthEndpoint.swift b/GAMSS/Sources/Data/Endpoint/AuthEndpoint.swift index a7381ba..a9c41b4 100644 --- a/GAMSS/Sources/Data/Endpoint/AuthEndpoint.swift +++ b/GAMSS/Sources/Data/Endpoint/AuthEndpoint.swift @@ -9,11 +9,17 @@ import Foundation enum AuthEndpoint: Endpoint { case login(LoginRequestDTO) + case logout + case reissueToken(ReissueTokenRequestDTO) var path: String { switch self { case .login: return "/api/auth/login" + case .logout: + return "/api/auth/logout" + case .reissueToken: + return "/api/auth/reissue" } } @@ -21,13 +27,30 @@ enum AuthEndpoint: Endpoint { switch self { case .login: return .post + case .logout: + return .post + case .reissueToken: + return .post } } - var body: Encodable? { + var parameters: [RequestParameter] { switch self { case let .login(request): - return request + return [.body(request)] + case .logout: + return [] + case let .reissueToken(request): + return [.body(request)] + } + } + + var header: HTTPHeader { + switch self { + case .login, .reissueToken: + return .default + case .logout: + return .authorization } } } diff --git a/GAMSS/Sources/Data/Endpoint/CardEndpoint.swift b/GAMSS/Sources/Data/Endpoint/CardEndpoint.swift new file mode 100644 index 0000000..c6623d2 --- /dev/null +++ b/GAMSS/Sources/Data/Endpoint/CardEndpoint.swift @@ -0,0 +1,79 @@ +// +// CardEndpoint.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +enum CardEndpoint: Endpoint { + case fetchCards(date: String) + case createCard(CreateCardRequestDTO) + case deleteAllCards + case fetchCard(cardId: String) + case deleteCard(cardId: String) + case fetchMonthlyCards(yearMonth: String) + case deleteCardsByEmotion(emotion: String) + + var path: String { + switch self { + case .fetchCards: + return "/api/cards" + case .createCard: + return "/api/cards" + case .deleteAllCards: + return "/api/cards" + case let .fetchCard(cardId): + return "/api/cards/\(cardId)" + case let .deleteCard(cardId): + return "/api/cards/\(cardId)" + case .fetchMonthlyCards: + return "/api/cards/monthly" + case let .deleteCardsByEmotion(emotion): + return "/api/cards/emotions/\(emotion)" + } + } + + var method: HTTPMethod { + switch self { + case .fetchCards: + return .get + case .createCard: + return .post + case .deleteAllCards: + return .delete + case .fetchCard: + return .get + case .deleteCard: + return .delete + case .fetchMonthlyCards: + return .get + case .deleteCardsByEmotion: + return .delete + } + } + + var parameters: [RequestParameter] { + switch self { + case let .fetchCards(date): + return [.query(["date": date])] + case let .createCard(request): + return [.body(request)] + case .deleteAllCards: + return [] + case .fetchCard: + return [] + case .deleteCard: + return [] + case let .fetchMonthlyCards(yearMonth): + return [.query(["yearMonth": yearMonth])] + case .deleteCardsByEmotion: + return [] + } + } + + var header: HTTPHeader { + .authorization + } +} diff --git a/GAMSS/Sources/Data/Endpoint/ChatEndpoint.swift b/GAMSS/Sources/Data/Endpoint/ChatEndpoint.swift new file mode 100644 index 0000000..08a8a9d --- /dev/null +++ b/GAMSS/Sources/Data/Endpoint/ChatEndpoint.swift @@ -0,0 +1,94 @@ +// +// ChatEndpoint.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +enum ChatEndpoint: Endpoint { + case endChat(chatId: Int) + case createMessage(CreateMessageRequestDTO) + case createComment(CreateCommentRequestDTO) + case createReply(messageId: Int) + case updateTitle(chatId: String, UpdateChatTitleRequestDTO) + case fetchChats(date: String) + case fetchMessages(chatId: String) + case searchChats(keyword: String, page: Int, size: Int) + case fetchIncompleteChats + case deleteChat(chatId: String) + + var path: String { + switch self { + case let .endChat(chatId): + return "/api/conversations/\(chatId)/end" + case .createMessage: + return "/api/conversations/messages" + case .createComment: + return "/api/conversations/messages/comments" + case let .createReply(messageId): + return "/api/conversations/messages/comments/\(messageId)" + case let .updateTitle(chatId, _): + return "/api/conversations/\(chatId)/title" + case .fetchChats: + return "/api/conversations" + case let .fetchMessages(chatId): + return "/api/conversations/\(chatId)/messages" + case .searchChats: + return "/api/conversations/search" + case .fetchIncompleteChats: + return "/api/conversations/incomplete" + case let .deleteChat(chatId): + return "/api/conversations/\(chatId)" + } + } + + var method: HTTPMethod { + switch self { + case .endChat, + .createMessage, + .createComment, + .createReply: + return .post + case .updateTitle: + return .patch + case .fetchChats, + .fetchMessages, + .searchChats, + .fetchIncompleteChats: + return .get + case .deleteChat: + return .delete + } + } + + var parameters: [RequestParameter] { + switch self { + case .endChat: + return [] + case let .createMessage(request): + return [.body(request)] + case let .createComment(request): + return [.body(request)] + case .createReply: + return [] + case let .updateTitle(_, request): + return [.body(request)] + case let .fetchChats(date): + return [.query(["date": date])] + case .fetchMessages: + return [] + case let .searchChats(keyword, page, size): + return [.query(["keyword": keyword, "page": "\(page)", "size": "\(size)"])] + case .fetchIncompleteChats: + return [] + case .deleteChat: + return [] + } + } + + var header: HTTPHeader { + .authorization + } +} diff --git a/GAMSS/Sources/Data/Endpoint/MemberEndpoint.swift b/GAMSS/Sources/Data/Endpoint/MemberEndpoint.swift new file mode 100644 index 0000000..ebd8155 --- /dev/null +++ b/GAMSS/Sources/Data/Endpoint/MemberEndpoint.swift @@ -0,0 +1,56 @@ +// +// MemberEndpoint.swift +// GAMSS +// +// Created by 이건준 on 8/8/26. +// + +import Foundation + +enum MemberEndpoint: Endpoint { + case fetchMyProfile + case updateNickname(UpdateNicknameRequestDTO) + case deleteAccount + case fetchMyTokenUsage + + var path: String { + switch self { + case .fetchMyProfile: + return "/api/members/me" + case .updateNickname: + return "/api/members/me/nickname" + case .deleteAccount: + return "/api/members/me" + case .fetchMyTokenUsage: + return "/api/members/me/token-usage" + } + } + + var method: HTTPMethod { + switch self { + case .fetchMyProfile: + return .get + case .updateNickname: + return .patch + case .deleteAccount: + return .delete + case .fetchMyTokenUsage: + return .get + } + } + + var parameters: [RequestParameter] { + switch self { + case .fetchMyProfile: + return [] + case let .updateNickname(request): + return [.body(request)] + case .deleteAccount: + return [] + case .fetchMyTokenUsage: + return [] + } + } + + var header: HTTPHeader { .authorization } +}