LoginSignup
3
1

More than 1 year has passed since last update.

[Swift]RxSwift×MoyaでAPI通信してみる

Posted at

はじめに

API通信でおなじみのMoyaですがRxMoyaも備わっているのでRxSwiftと絡めた実装をやってみます。

シンプルに、Qiitaで「iOS」というタグでAPIを叩きます。

ソースコード

まずはAPI

API

QiitaAPI.swift
import Foundation
import Moya

enum QiitaError: Error {
    case error
}

enum QiitaAPI {
    case user
}

extension QiitaAPI: TargetType {
    var baseURL: URL {
        guard let url = URL(string: "https://qiita.com/api/v2/") else {
            fatalError("base URL error")
        }
        return url
    }

    var path: String {
        switch self {
        case .user:
            return "tags/\(QiitaSearchTag.tag)/items"
        }
    }

    var method: Moya.Method {
        return Moya.Method.get
    }

    var sampleData: Data {
        return Data()
    }

    var task: Task {
        return .requestPlain
    }

    var headers: [String: String]? {
        return nil
    }
}

QiitaSearchTag.tagを作成して外部で定数化しました。

Model

QiitaModel.swift
import Foundation

struct QiitaModel: Decodable {
    var title: String?
    var user: QiitaUser
    let url: String?
}

struct QiitaUser: Decodable {
    var profileImageUrl: String?

    enum CodingKeys: String, CodingKey {
        case profileImageUrl = "profile_image_url"
    }
}
 

ViewModel

QiitaViewModel.swift
import Foundation
import Moya
import RxCocoa
import RxMoya
import RxSwift

final class QiitaViewModel {

    var models = BehaviorRelay<[QiitaModel]>(value: [])
    private var disposeBag = DisposeBag()
    let provider = MoyaProvider<QiitaAPI>()

    func requestDataSource() {
        provider.rx.request(.user)
            .filterSuccessfulStatusCodes()
            .map([QiitaModel].self)
            .subscribe(onSuccess: { (response) in
                self.models.accept(response)
            }) { (error) in
                print(error)
            }
            .disposed(by: disposeBag)
    }
}

View(ViewController)

QiitaClientViewController

import RxSwift
import UIKit

final class QiitaClientViewController: UIViewController {

        #//tableViewのセットアップは省略

    private let viewModel = QiitaViewModel()
    private var disposeBag = DisposeBag()

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

    private func bind() {
        viewModel.models
            .bind(to: tableView.rx.items(cellIdentifier: tableViewCell, cellType: TableViewCell.self)) { _, element, cell in cell.configure(model: element) }.disposed(by: disposeBag)

        tableView.rx.modelSelected(QiitaModel.self)
            .subscribe(onNext: { response in
                guard let url = response.url,
                      let _url = URL(string: url) else {
                    return
                }
                UIApplication.shared.open(_url, options: [:], completionHandler: nil)
            })
            .disposed(by: disposeBag)
    }

}

tableView箇所の記述が劇的にスッキリしましたね。

使い方は徐々になれるしかないと思いました。

間違っている箇所やより良い書き方があればご指摘お願いします。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1