[RxSwift] AirPortClone: Networking

Junyoung Park·2022년 12월 23일
0

RxSwift

목록 보기
15/25
post-thumbnail

#3 Alamofire RxSwift HTTP REST Api Integration - RxSwift MVVM Coordinator iOS App

AirPortClone: Networking

구현 목표

  • Alamofire를 통한 네트워크 통신

구현 태스크

  • 프로토콜 + 모듈화를 통한 Http 통신 서비스
  • 뷰 모델의 이니셜라이즈 단에서 해당 통신 서비스를 통한 데이터 패치

핵심 코드

import Alamofire
import Foundation

protocol HttpRouter {
    var baseUrlString: String { get }
    var path: String { get }
    var method: HTTPMethod { get }
    var headers: HTTPHeaders? { get }
    var parameters: Parameters? { get }
    func body() throws -> Data?
    func request(usingHttpService service: HttpService) throws -> DataRequest
}

extension HttpRouter {
    var parameters: Parameters? { return nil }
    var headers: HTTPHeaders? { return nil }
    func body() throws -> Data? { return nil }
    func asUrlRequest() throws -> URLRequest {
        var url = try baseUrlString.asURL()
        url.appendPathComponent(path)
        var request = try URLRequest(url: url, method: method, headers: headers)
        request.httpBody = try body()
        return request
    }
    func request(usingHttpService service: HttpService) throws -> DataRequest {
        return try service.request(asUrlRequest())
    }
}
  • Http 통신을 간편하게 관리하는 프레임워크 Alamofire 사용
  • 프로토콜을 통해 Http 통신 라우터
  • 디폴트 값이 존재한다면 익스텐션을 통해 관리
import Foundation
import Alamofire

protocol HttpService {
    var sessionManager: Session { get set }
    func request(_ urlRequest: URLRequestConvertible) -> DataRequest
}
  • 해당 HttpService 또한 위의 라우터에서 사용하는 프로토콜
import Alamofire

class AirportHttpService: HttpService {
    var sessionManager: Session = Session.default
    
    func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
        return sessionManager.request(urlRequest).validate(statusCode: 200..<400)
    }
}
  • 실제 API가 사용할 Http 통신 서비스는 디폴트 세션을 사용하면서 통신 상태가 적합한 경우 URL 요청
import Alamofire

enum AirportHttpRouter {
    case getAirports
}

extension AirportHttpRouter: HttpRouter {
    
    var baseUrlString: String {
        return "https://gist.githubusercontent.com/tdreyno/4278655/raw/7b0762c09b519f40397e4c3e100b097d861f5588"
    }
    
    var path: String {
        switch self {
        case .getAirports: return "airports.json"
        }
    }
    
    var method: HTTPMethod {
        switch self {
        case .getAirports: return .get
        }
    }
}
  • 상기 프로토콜을 통한 공항 데이터를 얻어내기 위한 커스텀 Http 라우터

import Foundation
import RxSwift

protocol AirportAPI {
    func fetchAirports() -> Single<AirportResponse>
}
  • API를 통한 데이터 패치 함수를 프로토콜을 통해 표현
  • Single로 감싸주기 위한 RxSwift
import Foundation
import RxSwift

class AirportService {
    static let shared: AirportService = AirportService()
    private lazy var httpService = AirportHttpService()
    
    private init() {}
}

extension AirportService: AirportAPI {
    func fetchAirports() -> Single<AirportResponse> {
        return Single.create { [httpService] single -> Disposable in
            do {
                try AirportHttpRouter
                    .getAirports
                    .request(usingHttpService: httpService)
                    .responseDecodable(of: AirportResponse.self, completionHandler: { response in
                        switch response.result {
                        case .success(let airports):
                            print("Airports: \(airports)")
                            single(.success(airports))
                        case .failure(let error): print(error.localizedDescription)
                        }
                    })
            } catch {
                
            }
            return Disposables.create()
        }
    }
}
  • 상기 선언한 httpServiceAirportService 싱글턴을 통해 공항 데이터를 패치
func process() {
        airportService
            .fetchAirports()
            .map({print("Airports: \($0)")})
            .subscribe()
            .disposed(by: disposeBag)
    }
  • 검색 뷰 모델 이니셜라이즈 단에서 곧바로 호출되는 API 서비스 싱글턴 모델의 데이터 패치 함수
  • 리턴받은 데이터를 곧바로 뷰 모델이 가지고 있는 데이터에 연결, 뷰 컨트롤러에 바인딩될 예정
profile
JUST DO IT

0개의 댓글