[Library] Moya

E_H·2021년 9월 24일
0

Library

목록 보기
1/1

(img src = "https~png" width="30%" 했는데 실제 이미지 크기조절이 안되네요.. 혹시 해결책 아시는분 ..)

Moya?

moya는 enum을 사용하여 네트워크 요청을 type safe한 방식으로
alamofire를 한 번 더 감싼 네트워킹 라이브러리입니다.

일반적인 통신API인 URLSession과 Alamofire를 이용하면
통신기능을 구현할 수 있지만 어디서든 접근할 수 있어

어디서 작성할지에 대해 혼란을 야기할 수 있습니다.

이런 구성을 보완하기 위해 Moya는 다음과 같은 모습으로 구성되어 있습니다.

moya는 enum 타입과 프로토콜을 사용하여 type safe하다는 특징이 있습니다.

Moya 체험

기초적인 작성법은 Basic Usage Moya에 있으며
저는 github search API를 사용하여 간단한 repo들을 나타내 보겠습니다.

기본적인 UI 구성은 searchBar와 리스트를 나타내기 위한 collectionView로 구현되어있습니다.

struct RepositoryModel: Codable {
    
    let items: [RepositoryItemModel]
}

struct RepositoryItemModel: Codable {
    let fullName: String
    let description: String?
    
    enum CodingKeys: String, CodingKey {
        case fullName = "full_name"
        case description
    }
}

먼저 search respository에 맞게 모델을 작성합니다.

저는 title과 subtitle만 나타내기 위해
repo fullName과 description만 가져오도록 하겠습니다.

moya는 TargetType이라는 프로토콜을 사용하여
URL과 Path, Method 등을 정의할 수 있습니다.

struct APIservice: MoyaProtocol {
    
    enum GithubSearch: TargetType {
        
        case search(query: String)
        
        var baseURL: URL {
            return URL(string: "https://api.github.com/")!
        }
        
        var path: String {
            switch self {
            case .search(_):
                return "search/repositories"
            }
        }
        
        var method: Moya.Method {
            .get
        }
        
        var task: Task {
            switch self {
            case let .search(query):
                return .requestParameters(parameters: ["q": query], encoding: URLEncoding())
            }
        }
        
        var headers: [String : String]? {
            nil
        }
    }
    
    
    let service = MoyaProvider<GithubSearch>()
    
    func fetchMoya(text: String, completion: @escaping (Result<RepositoryModel, Error>) -> Void) {
        
        service.request(.search(query: text)) { response in
            switch response {
            case .success(let data):
                if let decode = try? JSONDecoder().decode(RepositoryModel.self, from: data.data) {
                    completion(.success(decode))
                }
            case .failure(let err):
                print(err.localizedDescription)
                completion(.failure(err))
            }
        }
    }
}

TargetType이 service와 관련된 부분이라 생각하여 APIservice안에 위치시켰고 enum을 통해 필요한 기능을 정의했습니다.

지금은 search라는 하나의 기능을 사용하지만 search와 관련된
여러가지 기능을 열거형식으로 나열할 수 있으며
이것을 switch문을 통해 정의할 수 있습니다.

TargetType 프로토콜의 요구 프로퍼티들은 다음과 같습니다.

  • baseURL: URL타입으로 서버의 기본 URL
  • path: 서버의 baseURL 뒤에 추가할 Path
  • method: get, post 같은 HTTP Method
  • task: request에 사용될 파라미터
  • header: request에서 사용되는 header

그리고 extension으로 기본값이 선언되어있어 필수 요구사항은 아니지만
추가로 구현할 수 있는 프로퍼티는 다음과 같습니다.

  • validationType: 허용할 response 타입 (기본 .none)
  • sampleData: 테스트용 데이터 (기본 Data())
let service = MoyaProvider<GithubSearch>()
    
    func fetchMoya(text: String, completion: @escaping (Result<RepositoryModel, Error>) -> Void) {
        
        service.request(.search(query: text)) { response in
            switch response {
            case .success(let data):
                if let decode = try? JSONDecoder().decode(RepositoryModel.self, from: data.data) {
                    completion(.success(decode))
                }
            case .failure(let err):
                print(err.localizedDescription)
                completion(.failure(err))
            }
        }
    }

enum과 switch로 정의한 TargetType을
제네릭으로 구현된 MoyaProvider에 넣고 인스턴스를 생성합니다.
MoyaProvider 내부에 구현된 request를 통해 case를 넣고 response를 받도록 합니다.

받아온 데이터를 화면에 뿌리면 잘나오게 됩니다 👍

테스트해보기에 앞서 Moya를 통해 api 통신을 해보았습니다.

저는 그동안 alamofire와 urlsession을 통해서만 api작업을 해보았는데

매번 service 작성 시 url과 header, param 등을 작성해야하는게
귀찮더라구여

moya는 TargetType 프로토콜을 통해 이를 관리하기 쉽게 할 수 있어 좋았고
enum기반으로 기능구성이 되기 때문에 type safe하다는 장점이 있었습니다.

조만간 moya를 통해 테스트코드를 작성해보겠습니다.

0개의 댓글