Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Moya+RxSwiftで実現する!ReactiveなAPIリクエスト

satoshin21
October 02, 2017

 Moya+RxSwiftで実現する!ReactiveなAPIリクエスト

俺コン Vol.1 / Day. 1
https://orecon.connpass.com/event/63769/

satoshin21

October 02, 2017
Tweet

More Decks by satoshin21

Other Decks in Technology

Transcript

  1. Moya + RxSwi,Ͱ࣮ݱ͢Δʂ
    Reac%veͳAPIϦΫΤετ
    Զίϯ Vol.1 Day. 1
    @satoshin21
    @satoshin21 1

    View full-size slide

  2. INTRODUCE
    • @satoshin21
    • eureka, Inc.
    • Pairs JP iOS Applica• created Chainable Anima@satoshin21 2

    View full-size slide

  3. @satoshin21 3

    View full-size slide

  4. What's Moya?
    @satoshin21 4

    View full-size slide

  5. Whats' Moya?
    • Network abstrac.on layer
    • RxSwi6, Reac.veSwi6ͱͷ࿈ܞ͕σϑΥϧτͰՄೳ
    • encapsulates Alamofire
    • ϓϥάΠϯΛ࡞੒Մೳ
    • ίϛϡχςΟ͕׆ൃ ( ༷ʑͳExtension )
    @satoshin21 5

    View full-size slide

  6. How to implement Moya.TargetType
    public enum GitHub {
    case zen
    case userProfile(String)
    case userRepositories(String)
    }
    @satoshin21 6

    View full-size slide

  7. How to implement Moya.TargetType
    extension GitHub: TargetType {
    public var baseURL: URL { return URL(string: "https://api.github.com")! }
    public var path: String {
    switch self {
    case .userProfile(let name):
    return "/users/\(name.urlEscaped)"
    ...
    }
    }
    public var method: Moya.Method = .get
    public var parameters: [String: Any]? {
    ...
    }
    }
    @satoshin21 7

    View full-size slide

  8. How to request with RxSwi0 & Moya
    let githubProvider = MoyaProvider()
    githubProvider.request(.userProfile("satoshin21")).subscribe { event in
    switch event {
    case let .next(response):
    let jsonString = try? response.mapString()
    message = jsonString ?? message
    case let .error(error):
    print(error)
    default:
    break
    }
    }
    @satoshin21 8

    View full-size slide

  9. @satoshin21 9

    View full-size slide

  10. That's it?
    @satoshin21 10

    View full-size slide

  11. Sampleͷ՝୊
    • enumʹTargetTypeΛ࣮૷
    • ΤϯυϙΠϯτ͕૿͑Δͱ஍ࠈ
    • Observable
    • Response ParseΛຖ౓ߦ͏
    • APIKitͷΑ͏ʹType SafeͰ͸ͳ͍
    @satoshin21 11

    View full-size slide

  12. ཧ૝ܗ
    DoSomething()
    .asDriver(onErrorJustReturn: nil)
    .drive(imageView.rx.image)
    .addDisposableTo(disposeBag)
    @satoshin21 12

    View full-size slide

  13. Moya Customiza-on for Pairs(jp)
    • enum to struct
    • Type safeͳObservable
    • Type Erasure
    @satoshin21 13

    View full-size slide

  14. @satoshin21 14

    View full-size slide

  15. enum to struct
    enum API { }
    extension API {
    enum Community {}
    }
    // Community API
    extension API.Community {
    /// ίϛϡχςΟ৘ใऔಘ
    struct GetSingle: PairsTargetType { ... }
    /// Search
    struct Search: PairsTargetType { ... }
    }
    @satoshin21 15

    View full-size slide

  16. enum to struct
    let communitySearch = API.Community.Search()
    @satoshin21 16

    View full-size slide

  17. PairsTargetType
    protocol PairsTargetType: TargetType, ObservableType {
    /// DecodedResponseType
    associatedtype D
    /// ObservableType.EʹόΠϯυͤ͞ΔͨΊ
    associatedtype E
    /// Ϩεϙϯε͔ΒೝΊ͍ͯΔܗࣜ΁σίʔυ͢ΔʢJSONͳͲʣ
    func decodeResponse(_ response: Moya.Response) throws -> D
    /// Ϩεϙϯε৘ใ͔Β׬ྃ·ͰͷObservableΛ࡞੒͢Δ
    func didDecodeData(_ responseData: D) -> Observable
    }
    @satoshin21 17

    View full-size slide

  18. implements PairsTargetType
    struct GetCampaign: PairsTargetType {
    // Moya.Response -> JSON
    typealias D = JSON
    // JSON -> [Community]
    typealias E = [Community]
    func didDecodeData(_ responseData: JSON) -> Observable<[Community]> {
    // JSON͔Β[Community]΁ͷϚοϐϯά΍DBͷอଘͳͲ
    let communities = ...
    return communities
    }
    }
    @satoshin21 18

    View full-size slide

  19. PairsTargetTypeͷObservableԽ
    extension PairsTargetType {
    func subscribe(_ observer: O) -> Disposable where O.E == E {
    // APIϦΫΤετ -> decodeResponse(response)ͰMoya.Response͔Βσίʔυ
    let requestData = Observable.create { (observer) in
    let cancellable = API.provider.request(.init(target: self),
    completion: { (result) in
    switch result {
    case .success(let response):
    let responseData = try self.decodeResponse(response)
    observer.onNext(responseData)
    observer.onCompleted()
    }
    )
    return Disposables.create(with: cancellable.cancel)
    }
    // σίʔυ͞ΕͨΦϒδΣΫτ(ओʹJSON)͔ΒϚοϐϯά͞ΕͨΦϒδΣΫτ΁
    return requestData
    .flatMap(self.didDecodeData)
    .subscribe(observer)
    }
    @satoshin21 19

    View full-size slide

  20. RxMoyaProvider
    extension API {
    fileprivate static let provider = API.Provider()
    // PairsTargetTypeΛ࣮૷ͨ͠ϦΫΤετͷॲཧΛߦ͏
    fileprivate class Provider: RxMoyaProvider {
    init() { }
    }
    }
    @satoshin21 20

    View full-size slide

  21. Binding
    API.Image.Get()
    .asDriver(onErrorJustReturn: nil)
    .drive(imageView.rx.image)
    .addDisposableTo(disposeBag)
    @satoshin21 21

    View full-size slide

  22. How we use Moya in Pairs
    // ίϛϡχςΟͱΧςΰϦʔΛऔಘ
    Observable
    .zip(
    API.Community.GetCommunities(),
    API.Community.GetCategories(),
    resultSelector: { $0 })
    .subscribe(
    onNext: { (communities: [Community], categories: [Category]) in
    // do something!
    }).addDisposableTo(disposeBag)
    @satoshin21 22

    View full-size slide

  23. Summary
    • Moyaࣗମ΋ڧྗ͕ͩɺΧελϚΠζͰΑΓReac)veʹ
    @satoshin21 23

    View full-size slide

  24. @satoshin21 24

    View full-size slide