conyang's iOS

[iOS] Moya를 사용한 Networking 본문

iOS

[iOS] Moya를 사용한 Networking

conyang 2024. 3. 17. 21:42

안녕하세요 코냥입니다:)

오늘 알아볼 것은 Moya라는 라이브러리 입니다!

 

제목에서 알 수 있듯이 Moya를 사용해서 네트워킹을 할 수 있습니다.

그렇다면 우리는 URLSession이나 Alamofire가 있는데 Moya는 뭐가 다르냐! 라고 궁금해하실 수 있는데욧!!.!

 

iOS에서 네트워킹을 할 때 기본적으로 쓰이는 게 URLSession입니다.

하지만 이 URLSession을 추상화하여 더 간편하게 사용할 수 있도록 한 라이브러리인 Alamofire를 많이들 사용합니다.

 

여기서 Alamofire를 한번 더 추상화하여 구현된 라이브러리가 바로 Moya입니다!

 

 

기존 구조에서 존재하는 문제점은 크게 3가지입니다.

  • 어디서 부터 시작할지 시작이 어렵다.
  • 유지보수가 어렵다.
  • 유닛 테스트 작성를 작성하기 어렵다.

이러한 문제점들을 가진 기존 구조에서 -> Moya를 사용하면

깔끔한 네트워크 계층 구조를 가지게 되고 네트워크 계층을 템플릿화하여 재사용할 수 있게 합니다.

 

 

Moya의 장점은 다음과 같습니다.

  • 컴파일시 API 엔드 포인트가 올바른지 체크한다.
  • Enum을 이용해서 언제, 어디에 사용될지 안전하게 (type-safe) 정의한다.
  • 유닛 테스트를 용이하게 만든다.

 

1. Moya 설치

Moya는 본인에게 가장 편한 방법으로 설치하시면 됩니다!(CocoaPods 또는 Swift Package Manager)

 

CocoaPods를 이용한 설치

- 프로젝트 폴더에서 pod init

- Podfile에 필요한 라이브러리 추가 -> pod install

pod 'Moya'
pod 'Moya/RxSwift'
pod 'Moya/ReactiveSwift'
pod 'Moya/Combine'

 

Swift Package Manager를 이용한 설치

- Xcode에서 File -> Add Packages

 https://github.com/Moya/Moya.git  입력 후 설치

 

 

 

2. 코드 작성

우선 http 통신을 위한 API를 준비해줍니다!

 

1. Enum을 사용한 API 목록 작성

enum UserAPI {
    case signUp(_ id: String,
                _ passwd: String)
    case signIn(_ id: String,
                _ passwd: String)
}

 

 

2. TargetType 작성

Moya는 MoyaProvider<TargetType>으로 request를 수행합니다.

방금 enum으로 작성한 API를 extension하고 Moya의 TargetType 프로토콜을 구현해줍니다.

 

TargetType 프로토콜의 property들은 다음과 같습니다.

  • baseURL - Server base URL 
  • path - baseURL 뒤에 추가 될 API Path(/sign-up, /comment, ...)
  • method - HTTP Method(GET, POST, DELETE, ...)
  • sampleData - 테스트를 위한 Mock Data
  • task - request에 사용될 파라미터
  • validationType - 허용할 response 정의 
    기존 Alamofire 의 .validate() 처럼 response의 StatusCode 에 따라 성공 유무를 판단한다.
  • headers - HTTP headers 
extension UserAPI: TargetType {
    var baseURL: URL { return URL(string: "http://")! }
    
    var path: String {
        switch self {
        case .signUp:
            return "/api/sign-up"
        case .signIn:
            return "/api/sign-in"
        }
    }
    
    var method: Moya.Method {
        switch self {
        case .signUp, .signIn:
            return .post
        }
    }
    
//    var sampleData: Data { }
    
    var task: Moya.Task {
        switch self {
        case let .signUp(id, passwd):
            var params: [String: String] = [
                "id": id,
                "passwd": passwd
            ]
            return .requestParameters(parameters: params, encoding: URLEncoding.queryString)
            
        case let .signIn(id, passwd):
            var params: [String: String] = [
                "id": id,
                "passwd": passwd
            ]
            return .requestParameters(parameters: params, encoding: URLEncoding.queryString)
        }
    }
    
    var headers: [String : String]? {
        return ["Content-type": "application/json"]
    }
    
    var validationType: ValidationType {
        return .successCodes
    }
}

 

 

 

3. Response struct 선언

request 요청 후 받은 Response를 저장할 구조체를 선언해줍니다.

Codable 프로토콜을 준수해야 합니다.

struct BaseResponse<T: Codable>: Codable {
    let isSuccess: Bool
    let code: String
    let message: String
    let result: T?
}

struct SignUpResponse: Codable {
    let memberId: Int
}

 

 

 

4. Make a Request

이제 준비가 됐으니 네트워크 요청을 해보아요!

 

먼저 네트워크 요청을 수행할 Moya Provider 인스턴스를 생성해줍니다.

let provider = MoyaProvider<UserAPI>()
        
provider.request(.signUp("user23", "123423")) { response in
    switch response {
    case let .success(response):
        let response = try? response.map(BaseResponse<SignUpResponse>.self)
        guard let memberId = response?.result?.memberId else { return }
        UserDefaults.standard.set(memberId, forKey: "memberId")
        self.textMessage.text = "회원가입에 성공했습니다."

    case let .failure(error):
        print(error.localizedDescription)
    }
}

 

Moya Proivder는 제네릭 타입으로 TargetType 프로토콜을 받고 있습니다.

이 인스턴스를 통해 원하는 API로 네트워크 요청이 가능합니다.

 

반환되는 response는 Result<Response, MoyaError> 형태입니다.

 

 

 

 

 

 

 

 

[참고]

https://github.com/Moya/Moya

https://velog.io/@parkgyurim/iOS-Moya