본문 바로가기
iOS_오픈소스 라이브러리😎

[iOS_OpenSource] Swift API 통신 쉽게하기 (Moya) _ 5

by 개발하는윤기사 2023. 10. 25.
728x90
반응형

 

안녕하세요~ 개발하는 윤기사입니다!!

 

오늘 포스팅은 오픈소스 라이브러리 중 API 통신을 쉽게 하도록 도와주는 "Moya"를 준비해 왔습니다!

 

Moya가 모야?

 

Moya URLSession을 추상화한 Alamofire를 다시 추상화한 프레임워크로 Network Layer를 템플릿화 해서 재사용성을 높이고, 개발자가 request, response에만 신경을 쓰도록 해줍니다. 아래 그림과 같이 말이죠!

 

 

Moya 라이브러리에 가장 좋은 점은 코드가 가독성이 높고, 쉽게 사용 가능하다는 점이었습니다!

 

 

바로 시작해 보도록 하시죠!

 

 

저는 TMDB Open API를 이용했습니다!!

 

Movie Lists -> Popular를 이용했어요! 

https://developer.themoviedb.org/reference/movie-popular-list

 

Popular

Get a list of movies ordered by popularity.

developer.themoviedb.org

 

 

해당 API의 Response 값을 확인해 주고... 이 Response 값을 이용해서 DTO를 만들어주도록 하겠습니다!

{
  "page": 1,
  "results": [
    {
      "adult": false,
      "backdrop_path": "/628Dep6AxEtDxjZoGP78TsOxYbK.jpg",
      "genre_ids": [
        28,
        53
      ],
      "id": 575264,
      "original_language": "en",
      "original_title": "Mission: Impossible - Dead Reckoning Part One",
      "overview": "Ethan Hunt and his IMF team embark on their most dangerous mission yet: To track down a terrifying new weapon that threatens all of humanity before it falls into the wrong hands. With control of the future and the world's fate at stake and dark forces from Ethan's past closing in, a deadly race around the globe begins. Confronted by a mysterious, all-powerful enemy, Ethan must consider that nothing can matter more than his mission—not even the lives of those he cares about most.",
      "popularity": 4167.922,
      "poster_path": "/NNxYkU70HPurnNCSiCjYAmacwm.jpg",
      "release_date": "2023-07-08",
      "title": "Mission: Impossible - Dead Reckoning Part One",
      "video": false,
      "vote_average": 7.7,
      "vote_count": 1621
    },
    ...
    {
      "adult": false,
      "backdrop_path": "/2vFuG6bWGyQUzYS9d69E5l85nIz.jpg",
      "genre_ids": [
        28,
        12,
        878
      ],
      "id": 667538,
      "original_language": "en",
      "original_title": "Transformers: Rise of the Beasts",
      "overview": "When a new threat capable of destroying the entire planet emerges, Optimus Prime and the Autobots must team up with a powerful faction known as the Maximals. With the fate of humanity hanging in the balance, humans Noah and Elena will do whatever it takes to help the Transformers as they engage in the ultimate battle to save Earth.",
      "popularity": 674.774,
      "poster_path": "/gPbM0MK8CP8A174rmUwGsADNYKD.jpg",
      "release_date": "2023-06-06",
      "title": "Transformers: Rise of the Beasts",
      "video": false,
      "vote_average": 7.5,
      "vote_count": 3384
    }
  ],
  "total_pages": 40527,
  "total_results": 810535
}

 

🍎 QuickType.io를 이용하면 Json Type을 Swift에서 사용할 수 있게 변환해 줍니다!! 꿀팁!

 

 

Convert JSON to Swift, C#, TypeScript, Objective-C, Go, Java, C++ and more<!-- --> • quicktype

{ "people": [ { "name": "Atticus", "high score": 100 }, { "name": "Cleo", "high score": 900 }, { "name": "Orly" }, { "name": "Jasper" } ] } Provide sample JSON files, URLs, JSON schemas, or GraphQL queries.

quicktype.io

 

 

1️⃣ TMDB API Response DTO 설정

import Foundation

struct TmdbDTO: Codable {
    let page: Int
    let results: [MovieDetail]
    let totalPages, totalResults: Int

    enum CodingKeys: String, CodingKey {
        case page, results
        case totalPages = "total_pages"
        case totalResults = "total_results"
    }
}

// MARK: - Result
struct MovieDetail: Codable {
    let adult: Bool
    let backdropPath: String
    let genreIDS: [Int]
    let id: Int
    let originalLanguage: OriginalLanguage
    let originalTitle, overview: String
    let popularity: Double
    let posterPath, releaseDate, title: String
    let video: Bool
    let voteAverage: Double
    let voteCount: Int

    enum CodingKeys: String, CodingKey {
        case adult
        case backdropPath = "backdrop_path"
        case genreIDS = "genre_ids"
        case id
        case originalLanguage = "original_language"
        case originalTitle = "original_title"
        case overview, popularity
        case posterPath = "poster_path"
        case releaseDate = "release_date"
        case title, video
        case voteAverage = "vote_average"
        case voteCount = "vote_count"
    }
}

enum OriginalLanguage: String, Codable {
    case en = "en"
    case es = "es"
    case pt = "pt"
}

 

2️⃣ API Target enum 선언

- TMDBService라는 enum을 만들어줍니다.

import Foundation
import Moya

enum TMDBService {
    case popularMovies(page: Int)
}

 

3️⃣ TargetType 설정

Moya는 MoyaProvider<TargetType>으로 request를 수행하기 때문에, API가 TargetType 프로토콜을 구현해야 합니다!

extension을 만들어 TMDBService이 TargetType 프로토콜을 채택하도록 하고, 아래와 같은 프로퍼티들을 구현합니다.

extension TMDBService: TargetType {
    var baseURL: URL {
        return URL(string: "https://api.themoviedb.org/3")!
    }
    
    var path: String {
        switch self {
        case .popularMovies:
            return "/movie/popular"
        }
    }
    
    var method: Moya.Method {
        return .get
    }
    
    var task: Task {
        switch self {
        case .popularMovies(let page):
            return .requestParameters(parameters: [
                "api_key": EndPoint.api_key,
                "page": page,
                "language": "en"
            ], encoding: URLEncoding.queryString)
        }
    }
    
    var sampleData: Data {
        return Data()
    }
    
    var headers: [String: String]? {
        return ["Content-type": "application/json"]
    }
}
  • baseURL: base가 되는 도메인
  • path: 도메인 뒤에 추가되는 path (/movie 등)
  • method: HTTP method (GET, POST, PUT, DELETE)
  • sampleData: 테스트용 Mock Data
  • task: request에 사용될 파라미터 
    • requestPlain: no param
    • requestParameters(parameter: , encoding: )
  • headers: HTTP Header
    • Content-type : "application/json" or "application/x-www-form-urlencoded"

 

 

4️⃣ API 통신하기 - Request 보내고, Response 처리하기

func getMovieTitle(_ completion: @escaping (String) -> () ) {

    let provider = MoyaProvider<TMDBService>()
    
    provider.request(.popularMovies(page: 1)) { result in

        switch result {
        case .success(let response):
            do {
                let movies = try JSONDecoder().decode(TmdbDTO.self, from: response.data)
                let moviesTitleList = movies.results.map { details in
                    details.originalTitle
                }
                let movieTitle = moviesTitleList.randomElement() ?? "영화 제목 없음."
                completion(movieTitle)
            } catch {
                print("error")
            }
        case .failure(let error):
            print(error.localizedDescription)
        }
    }
}

 

5️⃣ Response 값 이용하기

getMovieTitle { [weak self] title in
    guard let self else { return }
    print(title)
}

 

 

 

 

 

 

 

GitHub - Moya/Moya: Network abstraction layer written in Swift.

Network abstraction layer written in Swift. Contribute to Moya/Moya development by creating an account on GitHub.

github.com

728x90
반응형