diff --git a/Service/Sources/Domain/BookDomain/API/BookAPI.swift b/Service/Sources/Domain/BookDomain/API/BookAPI.swift new file mode 100644 index 0000000..6c8de19 --- /dev/null +++ b/Service/Sources/Domain/BookDomain/API/BookAPI.swift @@ -0,0 +1,69 @@ +import Foundation +import Moya + +public enum BookAPI { + case writeBook(req: BookInfoRequestDTO) + case bookList + case bookDetail(book_id: Int) + case modifyBook(book_id: Int, req: BookInfoRequestDTO) + case deleteBook(book_id: Int) +} + +extension BookAPI: MindWayAPI { + public typealias ErrorType = BookDomainError + + public var domain: MindWayDomain { + .book + } + + public var urlPath: String { + switch self { + case .writeBook, .bookList: + return "" + case let .bookDetail(book_id), + let .modifyBook(book_id, _), + let .deleteBook(book_id): + return "/\(book_id)" + } + } + + public var method: Moya.Method { + switch self { + case .bookList, .bookDetail: + return .get + case .writeBook: + return .post + case .modifyBook: + return .patch + case .deleteBook: + return .delete + } + } + + public var task: Moya.Task { + switch self { + case let .writeBook(req): + return .requestJSONEncodable(req) + case let .modifyBook(_, req): + return .requestJSONEncodable(req) + case .bookList, .bookDetail, .deleteBook: + return .requestPlain + } + } + + public var jwtTokenType: JwtTokenType { + switch self { + default: + return .accessToken + } + } + + public var errorMap: [Int: ErrorType] { + switch self { + default: + return [ + 401: .unauthorized + ] + } + } +} diff --git a/Service/Sources/Domain/BookDomain/DTO/Response/FetchBookDetailInfoResponseDTO.swift b/Service/Sources/Domain/BookDomain/DTO/Response/FetchBookDetailInfoResponseDTO.swift new file mode 100644 index 0000000..77084c9 --- /dev/null +++ b/Service/Sources/Domain/BookDomain/DTO/Response/FetchBookDetailInfoResponseDTO.swift @@ -0,0 +1,23 @@ +import Foundation + +public struct FetchBookDetailInfoResponseDTO: Decodable { + public let title: String + public let plot: String + + public init( + title: String, + plot: String + ) { + self.title = title + self.plot = plot + } +} + +extension FetchBookDetailInfoResponseDTO { + func toDomain() -> BookDetialInfoEntity { + BookDetialInfoEntity( + title: title, + plot: plot + ) + } +} diff --git a/Service/Sources/Domain/BookDomain/DTO/Response/FetchBookInfoResponseDTO.swift b/Service/Sources/Domain/BookDomain/DTO/Response/FetchBookInfoResponseDTO.swift new file mode 100644 index 0000000..c1bd2a5 --- /dev/null +++ b/Service/Sources/Domain/BookDomain/DTO/Response/FetchBookInfoResponseDTO.swift @@ -0,0 +1,45 @@ +import Foundation + +public struct FetchBookInfoResponseDTO: Decodable { + public let book: [BookInfoResponseDTO] + + public init(book: [BookInfoResponseDTO]) { + self.book = book + } +} + +public struct BookInfoResponseDTO: Decodable { + public let id: Int + public let title: String + public let plot: String + public let created_at: Date + + public init( + id: Int, + title: String, + plot: String, + created_at: Date + ) { + self.id = id + self.title = title + self.plot = plot + self.created_at = created_at + } +} + +extension FetchBookInfoResponseDTO { + func toDomain() -> [BookInfoEntity] { + book.map { $0.toDomain() } + } +} + +extension BookInfoResponseDTO { + func toDomain() -> BookInfoEntity { + BookInfoEntity( + id: id, + title: title, + plot: plot, + created_at: created_at + ) + } +} diff --git a/Service/Sources/Domain/BookDomain/DataSource/RemoteBookDataSourceImpl.swift b/Service/Sources/Domain/BookDomain/DataSource/RemoteBookDataSourceImpl.swift new file mode 100644 index 0000000..59a8555 --- /dev/null +++ b/Service/Sources/Domain/BookDomain/DataSource/RemoteBookDataSourceImpl.swift @@ -0,0 +1,25 @@ +import Foundation + +public final class RemoteBookDataSourceImpl: BaseRemoteDataSource, RemoteBookDataSource { + public func writeBook(req: BookInfoRequestDTO) async throws { + try await request(.writeBook(req: req)) + } + + public func fetchBookList() async throws -> [BookInfoEntity] { + try await request(.bookList, dto: FetchBookInfoResponseDTO.self) + .toDomain() + } + + public func modifyBook(book_id: Int, req: BookInfoRequestDTO) async throws { + try await request(.modifyBook(book_id: book_id, req: req)) + } + + public func deleteBook(book_id: Int) async throws { + try await request(.deleteBook(book_id: book_id)) + } + + public func fetchBookDetail(book_id: Int) async throws -> BookDetailInfoEntity { + try await request(.bookDetail(book_id: book_id), dto: FetchBookDetailInfoResponseDTO.self) + .toDomain() + } +} diff --git a/Service/Sources/Domain/BookDomain/Entity/BookDetailInfoEntity.swift b/Service/Sources/Domain/BookDomain/Entity/BookDetailInfoEntity.swift new file mode 100644 index 0000000..07a99c4 --- /dev/null +++ b/Service/Sources/Domain/BookDomain/Entity/BookDetailInfoEntity.swift @@ -0,0 +1,14 @@ +import Foundation + +public struct BookDetailInfoEntity: Equatable { + public let title: String + public let plot: String + + public init( + title: String, + plot: String + ) { + self.title = title + self.plot = plot + } +} diff --git a/Service/Sources/Domain/BookDomain/Entity/BookInfoEntity.swift b/Service/Sources/Domain/BookDomain/Entity/BookInfoEntity.swift new file mode 100644 index 0000000..b730b80 --- /dev/null +++ b/Service/Sources/Domain/BookDomain/Entity/BookInfoEntity.swift @@ -0,0 +1,20 @@ +import Foundation + +public struct BookInfoEntity: Equatable { + public let id: Int + public let title: String + public let plot: String + public let created_at: Date + + public init( + id: Int, + title: String, + plot: String, + created_at: Date + ) { + self.id = id + self.title = title + self.plot = plot + self.created_at = created_at + } +} diff --git a/Service/Sources/Domain/BookDomain/Error/BookDomainError.swift b/Service/Sources/Domain/BookDomain/Error/BookDomainError.swift new file mode 100644 index 0000000..5b43699 --- /dev/null +++ b/Service/Sources/Domain/BookDomain/Error/BookDomainError.swift @@ -0,0 +1,14 @@ +import Foundation + +public enum BookDomainError: Error { + case unauthorized +} + +extension BookDomainError: LocalizedError { + public var errorDescription: String? { + switch self { + case .unauthorized: + return "권한이 없습니다." + } + } +} diff --git a/Service/Sources/Domain/BookDomain/Repository/BookRepositoryImpl.swift b/Service/Sources/Domain/BookDomain/Repository/BookRepositoryImpl.swift new file mode 100644 index 0000000..26b6b7e --- /dev/null +++ b/Service/Sources/Domain/BookDomain/Repository/BookRepositoryImpl.swift @@ -0,0 +1,31 @@ +import Foundation + +public struct BookRepositoryImpl: BookRepository { + private let remoteBookDataSource: any RemoteBookDataSource + + public init( + remoteBookDataSource: any RemoteBookDataSource + ) { + self.remoteBookDataSource = remoteBookDataSource + } + + public func writeBook(req: BookInfoRequestDTO) async throws { + try await remoteBookDataSource.writeBook(req: req) + } + + public func fetchBookList() async throws -> [BookInfoEntity] { + try await remoteBookDataSource.fetchBookList() + } + + public func modifyBook(req: BookInfoRequestDTO) async throws { + try await remoteBookDataSource.modifyBook(req: req) + } + + public func deleteBook() async throws { + try await remoteBookDataSource.deleteBook() + } + + public func fetchBookDetail() async throws -> BookDetailInfoEntity { + try await remoteBookDataSource.fetchBookDetail() + } +} diff --git a/Service/Sources/Domain/BookDomain/UseCase/DeleteBookUseCaseImpl.swift b/Service/Sources/Domain/BookDomain/UseCase/DeleteBookUseCaseImpl.swift new file mode 100644 index 0000000..16613cd --- /dev/null +++ b/Service/Sources/Domain/BookDomain/UseCase/DeleteBookUseCaseImpl.swift @@ -0,0 +1,13 @@ +import Foundation + +public struct DeleteBookUseCaseImpl: DeleteBookUseCase { + private let bookRepository: any BookRepository + + public init(bookRepository: any BookRepository) { + self.bookRepository = bookRepository + } + + public func execute() async throws { + try await bookRepository.deleteBook() + } +} diff --git a/Service/Sources/Domain/BookDomain/UseCase/FetchBookDetailUseCaseImpl.swift b/Service/Sources/Domain/BookDomain/UseCase/FetchBookDetailUseCaseImpl.swift new file mode 100644 index 0000000..a590b6e --- /dev/null +++ b/Service/Sources/Domain/BookDomain/UseCase/FetchBookDetailUseCaseImpl.swift @@ -0,0 +1,13 @@ +import Foundation + +public struct FetchBookDetailUseCaseImpl: FetchBookDetailUseCase { + private let bookRepository: any BookRepository + + public init(bookRepository: any BookRepository) { + self.bookRepository = bookRepository + } + + public func execute() async throws -> BookDetailInfoEntity { + try await bookRepository.fetchBookDetail() + } +} diff --git a/Service/Sources/Domain/BookDomain/UseCase/FetchBookListUseCaseImpl.swift b/Service/Sources/Domain/BookDomain/UseCase/FetchBookListUseCaseImpl.swift new file mode 100644 index 0000000..516e44b --- /dev/null +++ b/Service/Sources/Domain/BookDomain/UseCase/FetchBookListUseCaseImpl.swift @@ -0,0 +1,13 @@ +import Foundation + +public struct FetchBookListUseCaseImpl: FetchBookListUseCase { + private let bookRepository: any BookRepository + + public init(bookRepository: any BookRepository) { + self.bookRepository = bookRepository + } + + public func execute() async throws -> [BookInfoEntity]{ + try await bookRepository.fetchBookList() + } +} diff --git a/Service/Sources/Domain/BookDomain/UseCase/ModifyBookUseCaseImpl.swift b/Service/Sources/Domain/BookDomain/UseCase/ModifyBookUseCaseImpl.swift new file mode 100644 index 0000000..7eefe12 --- /dev/null +++ b/Service/Sources/Domain/BookDomain/UseCase/ModifyBookUseCaseImpl.swift @@ -0,0 +1,13 @@ +import Foundation + +public struct ModifyBookUseCaseImpl: ModifyBookUseCase { + private let bookRepository: any BookRepository + + public init(bookRepository: any BookRepository) { + self.bookRepository = bookRepository + } + + public func execute(req: BookInfoRequestDTO) async throws { + try await bookRepository.modifyBook(req: req) + } +} diff --git a/Service/Sources/Domain/BookDomain/UseCase/WriteBookUseCaseImpl.swift b/Service/Sources/Domain/BookDomain/UseCase/WriteBookUseCaseImpl.swift new file mode 100644 index 0000000..d2dd3c6 --- /dev/null +++ b/Service/Sources/Domain/BookDomain/UseCase/WriteBookUseCaseImpl.swift @@ -0,0 +1,13 @@ +import Foundation + +public struct WriteBookUseCaseImpl: WriteBookUseCase { + private let bookRepository: any BookRepository + + public init(bookRepository: any BookRepository) { + self.bookRepository = bookRepository + } + + public func execute(req: BookInfoRequestDTO) async throws { + try await bookRepository.writeBook(req: req) + } +} diff --git a/Service/Sources/Domain/GoalDomain/UseCase/SettingGoalUseCaseImpl.swift b/Service/Sources/Domain/GoalDomain/UseCase/SettingGoalUseCaseImpl.swift index 1737f94..6c8d625 100644 --- a/Service/Sources/Domain/GoalDomain/UseCase/SettingGoalUseCaseImpl.swift +++ b/Service/Sources/Domain/GoalDomain/UseCase/SettingGoalUseCaseImpl.swift @@ -7,7 +7,7 @@ public struct SettingGoalUseCaseImpl: SettingGoalUseCase { self.goalRepository = goalRepository } - public func execute() async throws { - try await goalRepository.settingGoal() + public func execute(req: SettingGoalRequestDTO) async throws { + try await goalRepository.settingGoal(req: req) } } diff --git a/Service/Sources/Interface/DTO/Book/Request/BookInfoRequestDTO.swift b/Service/Sources/Interface/DTO/Book/Request/BookInfoRequestDTO.swift new file mode 100644 index 0000000..1e81cf7 --- /dev/null +++ b/Service/Sources/Interface/DTO/Book/Request/BookInfoRequestDTO.swift @@ -0,0 +1,14 @@ +import Foundation + +public struct BookInfoRequestDTO: Encodable { + public let title: String + public let plot: String + + public init( + title: String, + plot: String + ) { + self.title = title + self.plot = plot + } +} diff --git a/Service/Sources/Interface/DTO/Request/SettingGoalRequestDTO.swift b/Service/Sources/Interface/DTO/Goal/Request/SettingGoalRequestDTO.swift similarity index 100% rename from Service/Sources/Interface/DTO/Request/SettingGoalRequestDTO.swift rename to Service/Sources/Interface/DTO/Goal/Request/SettingGoalRequestDTO.swift diff --git a/Service/Sources/Interface/DataSource/Book/RemoteBookDataSource.swift b/Service/Sources/Interface/DataSource/Book/RemoteBookDataSource.swift new file mode 100644 index 0000000..04617be --- /dev/null +++ b/Service/Sources/Interface/DataSource/Book/RemoteBookDataSource.swift @@ -0,0 +1,9 @@ +import Foundation + +public protocol RemoteBookDataSource { + func writeBook(req: BookInfoRequestDTO) async throws + func fetchBookList() async throws -> [BookInfoEntity] + func modifyBook(book_id: Int, req: BookInfoRequestDTO) async throws + func deleteBook(book_id: Int) async throws + func fetchBookDetail(book_id: Int) async throws -> BookDetailInfoEntity +} diff --git a/Service/Sources/Interface/Repository/Book/BookRepository.swift b/Service/Sources/Interface/Repository/Book/BookRepository.swift new file mode 100644 index 0000000..447b375 --- /dev/null +++ b/Service/Sources/Interface/Repository/Book/BookRepository.swift @@ -0,0 +1,9 @@ +import Foundation + +public protocol BookRepository { + func writeBook(req: BookInfoRequestDTO) async throws + func fetchBookList() async throws -> [BookInfoEntity] + func modifyBook(book_id: Int, req: BookInfoRequestDTO) async throws + func deleteBook(book_id: Int) async throws + func fetchBookDetail(book_id: Int) async throws -> BookDetailInfoEntity +} diff --git a/Service/Sources/Interface/UseCase/Book/DeleteBookUseCase.swift b/Service/Sources/Interface/UseCase/Book/DeleteBookUseCase.swift new file mode 100644 index 0000000..2513d0e --- /dev/null +++ b/Service/Sources/Interface/UseCase/Book/DeleteBookUseCase.swift @@ -0,0 +1,5 @@ +import Foundation + +public protocol DeleteBookUseCase { + func execute(book_id: Int) async throws +} diff --git a/Service/Sources/Interface/UseCase/Book/FetchBookDetailUseCase.swift b/Service/Sources/Interface/UseCase/Book/FetchBookDetailUseCase.swift new file mode 100644 index 0000000..7762d48 --- /dev/null +++ b/Service/Sources/Interface/UseCase/Book/FetchBookDetailUseCase.swift @@ -0,0 +1,5 @@ +import Foundation + +public protocol FetchBookDetailUseCase { + func execute(book_id: Int) async throws -> BookDetailInfoEntity +} diff --git a/Service/Sources/Interface/UseCase/Book/FetchBookListUseCase.swift b/Service/Sources/Interface/UseCase/Book/FetchBookListUseCase.swift new file mode 100644 index 0000000..dac462b --- /dev/null +++ b/Service/Sources/Interface/UseCase/Book/FetchBookListUseCase.swift @@ -0,0 +1,5 @@ +import Foundation + +public protocol FetchBookListUseCase { + func execute() async throws -> [BookInfoEntity] +} diff --git a/Service/Sources/Interface/UseCase/Book/ModifyBookUseCase.swift b/Service/Sources/Interface/UseCase/Book/ModifyBookUseCase.swift new file mode 100644 index 0000000..f8d7a6b --- /dev/null +++ b/Service/Sources/Interface/UseCase/Book/ModifyBookUseCase.swift @@ -0,0 +1,5 @@ +import Foundation + +public protocol ModifyBookUseCase { + func execute(book_id: Int, req: BookInfoRequestDTO) async throws +} diff --git a/Service/Sources/Interface/UseCase/Book/WriteBookUseCase.swift b/Service/Sources/Interface/UseCase/Book/WriteBookUseCase.swift new file mode 100644 index 0000000..30280c9 --- /dev/null +++ b/Service/Sources/Interface/UseCase/Book/WriteBookUseCase.swift @@ -0,0 +1,5 @@ +import Foundation + +public protocol WriteBookUseCase { + func execute(req: BookInfoRequestDTO) async throws +} diff --git a/Service/Sources/Interface/UseCase/Goal/SettingGoalUseCase.swift b/Service/Sources/Interface/UseCase/Goal/SettingGoalUseCase.swift index deb3622..dac9b5a 100644 --- a/Service/Sources/Interface/UseCase/Goal/SettingGoalUseCase.swift +++ b/Service/Sources/Interface/UseCase/Goal/SettingGoalUseCase.swift @@ -1,5 +1,5 @@ import Foundation public protocol SettingGoalUseCase { - func execute() async throws + func execute(req: SettingGoalRequestDTO) async throws }