Skip to content
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

[Feat] #14 - 네트워크 레이어 구현 및 클린아키텍쳐 예시코드 작성 #25

Merged
merged 7 commits into from
Oct 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ iOSInjectionProject/
!*.xcworkspace/contents.xcworkspacedata
**/xcshareddata/WorkspaceSettings.xcsettings

RecorDream-iOS/Projects/Modules/RD-Network/Sources/Environment/config.swift

Gemfile
Gemfile.lock

Expand Down
4 changes: 2 additions & 2 deletions RecorDream-iOS/Projects/Core/Sources/Util/JsonCoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import Foundation
*/

public enum Json {
static let encoder: JSONEncoder = {
public static let encoder: JSONEncoder = {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
return encoder
}()

static let decoder = JSONDecoder()
public static let decoder = JSONDecoder()
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
//

import Domain
import RD_Network

import Foundation

struct MyPageDTO {

extension DreamWriteResponse {
func toDomain() -> DreamWriteEntity {
return .init(userId: self.userId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,37 @@
// Copyright © 2022 RecorDream. All rights reserved.
//

import RxSwift
import Foundation

import Domain
import RD_Network

import RxSwift

public class DefaultDreamWriteRepository {

private let disposeBag = DisposeBag()

public init() {

private let recordService: RecordService

public init(recordService: RecordService) {
self.recordService = recordService
}
}

extension DefaultDreamWriteRepository: DreamWriteRepository {

public func writeDreamRecord(request: DreamWriteRequestEntity) -> Observable<DreamWriteEntity?> {
return Observable.create { observer in
self.recordService.writeDreamRecord(title: request.title, date: request.date, content: request.content, emotion: request.emotion, genre: request.genre, note: request.note, voice: request.voice)
.subscribe(onNext: { entity in
guard let entity = entity else { return observer.onCompleted() }
observer.onNext(entity.toDomain())
}, onError: { err in
observer.onError(err)
})
.disposed(by: self.disposeBag)
return Disposables.create()
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Domain
import RD_Network

import RxSwift

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,27 @@
import Foundation

public struct DreamWriteEntity {
public let userId: Int

public init(userId: Int) {
self.userId = userId
}
}

public struct DreamWriteRequestEntity {
public let title: String
public let date: String
public let content: String
public let emotion: Int
public let genre: [Int]
public let note: String? = nil
public let voice: URL? = nil

public init(title: String, date: String, content: String, emotion: Int, genre: [Int], note: String?, voice: URL?) {
self.title = title
self.date = date
self.content = content
self.emotion = emotion
self.genre = genre
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
// Created by Junho Lee on 2022/09/29.
//

import Foundation

import RxSwift

public protocol DreamWriteRepository {

func writeDreamRecord(request: DreamWriteRequestEntity) -> Observable<DreamWriteEntity?>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,39 @@
// Copyright © 2022 RecorDream. All rights reserved.
//

import Foundation

import RxSwift

public protocol DreamWriteUseCase {

func writeDreamRecord(request: DreamWriteRequestEntity)
var writeData: PublishSubject<DreamWriteEntity> { get set }
var writeFail: PublishSubject<Error> { get set }
}

public class DefaultDreamWriteUseCase {

private let repository: DreamWriteRepository
private let disposeBag = DisposeBag()


public var writeData = PublishSubject<DreamWriteEntity>()
public var writeFail = PublishSubject<Error>()

public init(repository: DreamWriteRepository) {
self.repository = repository
}
}

extension DefaultDreamWriteUseCase: DreamWriteUseCase {

public func writeDreamRecord(request: DreamWriteRequestEntity) {
self.repository.writeDreamRecord(request: request)
.compactMap { $0 }
.subscribe(onNext: { [weak self] entity in
guard let self = self else { return }
self.writeData.onNext(entity)
}, onError: { err in
self.writeFail.onNext(err)
})
.disposed(by: self.disposeBag)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import UIKit

import RD_DSKit
import RD_Network

typealias Factory = CoordinatorFactoryProtocol & ViewControllerFactory
typealias ViewControllerFactory = AuthViewControllerFactory & MainTabBarControllerFactory
Expand Down Expand Up @@ -40,7 +41,11 @@ open class DependencyContainer {

// MARK: Network services

// internal lazy var authNetworkServices = AuthNetworkServices(apiManager: self.apiManager)
internal lazy var authService = DefaultAuthService.shared
internal lazy var recordService = DefaultRecordService.shared
internal lazy var noticeService = DefaultNoticeService.shared
internal lazy var userService = DefaultUserService.shared
internal lazy var voiceService = DefaultVoiceService.shared

// MARK: - Public func

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ extension DependencyContainer: MainTabBarControllerFactory {
}

func instantiateDreamWriteVC() -> DreamWriteVC {
let repository = DefaultDreamWriteRepository()
let repository = DefaultDreamWriteRepository(recordService: self.recordService)
let useCase = DefaultDreamWriteUseCase(repository: repository)
let viewModel = DreamWriteViewModel(useCase: useCase)
let dreamWriteVC = DreamWriteVC()
Expand Down
Empty file.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// GeneralResponse.swift
// RD-NetworkTests
//
// Created by Junho Lee on 2022/10/14.
// Copyright © 2022 RecorDream. All rights reserved.
//

import Foundation

struct GeneralResponse<T> {
let success: Bool
let status: Int
let message: String?
let data: T?

enum CodingKeys: String, CodingKey {
case success
case status
case message
case data
}
}

extension GeneralResponse: Decodable where T: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
success = try container.decode(Bool.self, forKey: .success)
status = try container.decode(Int.self, forKey: .status)
message = try? container.decode(String.self, forKey: .message)
data = try? container.decode(T.self, forKey: .data)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// HeaderType.swift
// RD-NetworkTests
//
// Created by Junho Lee on 2022/10/14.
// Copyright © 2022 RecorDream. All rights reserved.
//

import Foundation

public enum HeaderType {
case `default`
case withToken
case multiPart
case multiPartWithToken
case reissuance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 reissuance는 언제 쓰이는 헤더타입인가요 ??!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Suyeon9911 토큰 재발급의 경우에 사용하는 케이스입니다! BaseService에서 헤더를 분기처리하는 곳을 보시면 reissuance의 경우에만 access와 refresh token 모두를 헤더에 실어서 보내주는 것을 확인할 수 있습니다. 저번 프로젝트에서 이런 방식으로 재발급을 처리했는데 레코드림의 경우에는 다른 방식(바디에 토큰을 보내는)을 사용할 수도 있을 것 같습니다. 논의하기 나름일듯~~

}

enum HTTPHeaderField: String {
case contentType = "Content-Type"
case authorization = "Authorization"

case access
case refresh = "refreshtoken"
}

enum HeaderContent: String {
case json = "application/json"
case multiPart = "multipart/form-data"
case accessTokenSerial = "액세스 토큰 스트링"
case refreshTokenSerial = "리프레시 토큰 스트링"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// NetworkResult.swift
// RD-NetworkTests
//
// Created by Junho Lee on 2022/10/14.
// Copyright © 2022 RecorDream. All rights reserved.
//

import Foundation

enum NetworkResult<T> {
case success(T)
case requestErr(T)
case pathErr
case serverErr
case networkFail
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// AFManager.swift
// RD-NetworkTests
//
// Created by Junho Lee on 2022/10/14.
// Copyright © 2022 RecorDream. All rights reserved.
//

import Foundation

import Alamofire

class Managers {

static let `default`: Session = {
var session = AF
let configuration = URLSessionConfiguration.af.default
configuration.timeoutIntervalForRequest = NetworkEnvironment.requestTimeOut
configuration.timeoutIntervalForResource = NetworkEnvironment.resourceTimeOut
let eventLogger = APIEventLogger()
let interceptor = AlamoInterceptor()
session = Session(configuration: configuration, interceptor: interceptor, eventMonitors: [eventLogger])
return session
}()

private init() { }
}

public extension Session {
func uploadMultipart(target: BaseRouter) -> UploadRequest {
return self.upload(multipartFormData: target.multipart, with: target)
}
}