Moya, RxSwift를 활용한 네트워킹

이번 프로젝트에서 리스트를 받아 부려주는 화면의 로직을
Moya를 활용하여 Reactive하게 짜보려고 한다

1. ResponseModel 작성

struct Student: Decodable {
    let id, certCount: Int
    let name, image: String
}

struct StudentsResponse: Decodable {
    let students: [Student]
}

2. API Service enum 작성

struct APIEnvironment {
    static let baseURL: URL(string: "https://baseurl.com")
}

enum StudentService {
    case getStudents
}

extension StudentService: TargetType {
    var baseURL: URL {
        return APIEnvironment.baseUrl
    }
    
    var path: String {
        return "/students"
    }
    
    var method: Moya.Method {
        return .get
    }
    
    var sampleData: Data {
        return Data()
    }
    
    var task: Task {
        return .requestPlain
    }
    
    var headers: [String : String]? {
        let accessToken = UserDefaults.standard.string(forKey: "userAccessToken")
        return ["Authorization": "Bearer \(accessToken)"]
    }
}

3. ViewModel 작성

class StudentViewModel {
    static let shared = StudentViewModel()

    private let disposeBag = DisposeBag()

    private let provider = MoyaProvider(StudentService)()

    let students = BehaviorRelay<[Student]>(value: [])

    init() {
        setupData()
    }
}

4. MoyaResponse를 Subscribe

extension StudentViewModel {
    private func requestStudents() -> Ovservable<StudentsResponse> {
        return provider.rx.request(.getStudents)
            .filterSuccessfulStatusCodes()
            .map(StudentsResponse.self)
            .asObservable()
    }

    private func setupData() {
        requestStudents().subscribe(onNext: { [weak self] response in
            guard let self = self else { return }
            self.students.accept(response.students)
        })
        .disposed(by: disposeBag)
    }
}

5. TableView에 ViewModel 데이터를 바인딩해줌

private let viewModel = StudentViewModel.shared

override func viewDidLoad() {
    super.viewDidLoad()
        
    bind(viewModel.student)
}

private func bind(_ dataSource: BehaviorRelay<[Student]>) {
    dataSource.bind(to: tableView.rx.items(
        cellIdentifier: StudentCell.identifier,
        cellType: StudentCell.self
    )) { index, student, cell in
        cell.setupData(student)
    }
    .disposed(by: disposeBag)
}