Moya api로 통신 연습 해보기

0 답변 글타래를 보이고 있습니다
  • 글쓴이
    • iJoom
      참가자
      • 글작성 : 8
      • 답글작성 : 1

      통신: Moya


      • Moya = urlSession , Alamofire를 한번더 감싼 통신 api 입니다.
      • 여행 데이터를 통신하고 보여주는 뷰에서 Moya를 활용해 통신을 해보았습니다.
      • 메소드의 분기처리 및 개별로 get , post를 설정해줄 수 있어서 편했습니다.
      struct BaseResponseModel<Decode: Decodable>: Decodable {
          let status: Int
          let data: Decode?
          let success: Bool
          let message: String?
      }
      
      • 데이터 통신 분기처리를 위한 모델 생성
      final class APIService {
      static let shared = APIService()
      private init() {}
      
      private let provider = MoyaProvider<APITarget>()
      
      func requestCityActivity(cityID: Int, completion: @escaping (Result<CityActivityResponseModel, Error>) -> Void) {
            provider.request(.cityActivity(cityID: cityID)) { result in
                switch result {
                case let .success(success):
                    let responseData = success.data
                    do {
                        let decoded = try JSONDecoder().decode(CityActivityResponseModel.self, from: responseData)
                        completion(.success(decoded))
                    } catch {
                        completion(.failure(error))
                    }
                case let .failure(error):
                    completion(.failure(error))
                }
            }
        }
      }
      
      • Activity Data 통신을 위한 APIService 메소드 정의

        typealias CityActivityResponseModel = BaseResponseModel&lt;[_CityActivityResponseModel]&gt;
        • typealias를 이용한 제네릭 모델 별칭 지정, 코드 간소화 및 가독성 개선
        @escaping (Result&lt;CityActivityResponseModel, Error&gt;)
        
        • Generic 부분 추가 설명 , 하나 이상의 타입 인자를 사용할 수 있으며, 꺽쇠 안에서 타입 인자 이름을 콤마로 분리하여 작성한다. (ex. <T, M>)
        • Result 의 원래 인자는 <Success, Failure>
        public protocol TargetType {
        
           /// The target's base `URL`.
           var baseURL: URL { get }
        
           /// The path to be appended to `baseURL` to form the full `URL`.
           var path: String { get }
        
           /// The HTTP method used in the request.
           var method: Moya.Method { get }
        
           /// Provides stub data for use in testing.
           var sampleData: Data { get }
        
           /// The type of HTTP task to be performed.
           var task: Task { get }
        
           /// The type of validation to perform on the request. Default is `.none`.
           var validationType: ValidationType { get }
        
           /// The headers to be used in the request.
           var headers: [String: String]? { get }
        }
        
        public extension TargetType {
        
           /// The type of validation to perform on the request. Default is `.none`.
           var validationType: ValidationType {
               return .none
           }
        }
        
      • Moya의 TargetType protocol 을 상속받아서 열거형으로 APITarget구현
        //
        
        import Moya
        
        enum APITarget: TargetType {
           case medianHotelRead(cityID: Int, subCategory: Int)
           case cityActivity(cityID: Int)
           case tripCreate(cityID: Int, body: TripCreateRequestModel)
           case medianFoodRead(cityID : Int)
        
           var baseURL: URL {
               return URL(string: "http://13.125.42.117:3000")!
           }
        
           var path: String {
               switch self {
               case let .medianHotelRead(cityID, subCategory):
                   return "/median/\(cityID)/\(subCategory)/hoteliOS/"
               case let .cityActivity(cityID):
                   return "/citys/\(cityID)/Activity"
               case let .tripCreate(cityID, _):
                   return "/trips/\(cityID)"
               case let .medianFoodRead(cityID):
                   return "/median/\(cityID)/food"
               }
           }
        
        // Moya의 method가 모야의 쉬우면서 편한 기능이라고 생각합니다.
        // 각 메소드가 get인지 post인지 일일이 설정이 가능하며, 협업시 각 메소드의 기능들을 보기 쉽게 구별할 수 있어서 코드의 가독성 또한 좋아집니다.
           var method: Method {
               switch self {
               case .medianHotelRead:
                   return .get
               case .cityActivity:
                   return .get
               case .tripCreate:
                   return .post
               case .medianFoodRead:
                   return .get
               }
               // case. sendA:
               // return .post
           }
        
           var sampleData: Data {
               return .init()
           }
        
           var task: Task {
               switch self {
               case .medianHotelRead:
                   return .requestPlain     
               case .cityActivity:
                   return .requestPlain
               case let .tripCreate(cityID, body):
                   let encoded = try! JSONEncoder().encode(body)
                   return .requestCompositeData(bodyData: encoded, urlParameters: ["CityId": cityID])
               case let .medianFoodRead(cityID):
                   return .requestPlain
               }
           }
        
           var headers: [String : String]? {
               return ["Content-Type": "application/json"]
           }
        }
        
        
        enum APITarget: TargetType {
        case medianHotelRead(cityID: Int, subCategory: Int)
        case cityActivity(cityID: Int)
        case tripCreate(cityID: Int, body: TripCreateRequestModel)
        case medianFoodRead(cityID : Int)
        
        
        var path: String {
        switch self {
        case let .cityActivity(cityID):
         return "/citys/\(cityID)/Activity"
         }
        }
        
        func requestCityActivity(cityID: Int, completion: @escaping (Result&lt;CityActivityResponseModel, Error&gt;) -&gt; Void) {
            provider.request(.cityActivity(cityID: cityID))
        
        • provider.request부분에서 .cityActivity부분이 APItarget을 사용 하는부분
        • provider.request( APITarget.cityActivity(cityID: cityID)) 축약형으로 표현
          override func viewDidAppear(_ animated: Bool) {
              let cityID = 1
              APIService.shared.requestCityActivity(cityID: cityID) { [weak self] result in
                  switch result {
                  case let .success(success):
                      guard let data = success.data else { return }
                      self?.responseModel = data
                  case let .failure(error):
                      print(error.localizedDescription)
                  }
              }
          }
      
      • viewDidAppear ViewLifeCycle에서 APIService의 분기별로 처리해 놓은 (싱클턴패턴) 정의 해놨던 request 함수호출
0 답변 글타래를 보이고 있습니다
  • 답변은 로그인 후 가능합니다.

logo landscape small

사업자번호 : 743-81-02195
통신판매업 신고번호 : 제 2022-충북청주-1278 호
고객센터 : 카카오톡채널 @yagom