Rodrigo
Rodrigo

Reputation: 19

How can I decode and deserialize json from 'the movie db' using VIPER?

I'm learning how to display data in a tableview through 'the movie db' api using the VIPER architecture but I still haven't learned how to decode and serialize JSON. I share my classes.

The JSON Response

    {
    "page": 1,
    "results": [
        {
            "adult": false,
            "backdrop_path": "/aTovumsNlDjof7YVoU5nW2RHaYn.jpg",
            "genre_ids": [
                27,
                53,
                10749
            ],
            "id": 616820,
            "original_language": "en",
            "original_title": "Halloween Ends",
            "overview": "Four years after the events of Halloween in 2018, Laurie has decided to liberate herself from fear and rage and embrace life. But when a young man is accused of killing a boy he was babysitting, it ignites a cascade of violence and terror that will force Laurie to finally confront the evil she can’t control, once and for all.",
            "popularity": 4845.496,
            "poster_path": "/3uDwqxbr0j34rJVJMOW6o8Upw5W.jpg",
            "release_date": "2022-10-12",
            "title": "Halloween Ends",
            "video": false,
            "vote_average": 6.9,
            "vote_count": 417
        },
        {
            "adult": false,
            "backdrop_path": "/5GA3vV1aWWHTSDO5eno8V5zDo8r.jpg",
            "genre_ids": [
                27,
                53
            ],
            "id": 760161,
            "original_language": "en",
            "original_title": "Orphan: First Kill",
            "overview": "After escaping from an Estonian psychiatric facility, Leena Klammer travels to America by impersonating Esther, the missing daughter of a wealthy family. But when her mask starts to slip, she is put against a mother who will protect her family from the murderous “child” at any cost.",
            "popularity": 3138.264,
            "poster_path": "/pHkKbIRoCe7zIFvqan9LFSaQAde.jpg",
            "release_date": "2022-07-27",
            "title": "Orphan: First Kill",
            "video": false,
            "vote_average": 6.8,
            "vote_count": 1046
        },
        {
            "adult": false,
            "backdrop_path": "/etP5jwlwvkNhwe7jnI2AyA6ZKrR.jpg",
            "genre_ids": [
                878
            ],
            "id": 575322,
            "original_language": "en",
            "original_title": "Звёздный разум",
            "overview": "After depleting Earth's resources for centuries, humankind's survival requires an exodus to outer space. An international expedition is quickly formed to find a suitable new planet, but when plans go awry, the crew is suddenly stranded without power on a strange planet, where something unimaginable lies in wait.",
            "popularity": 2457.191,
            "poster_path": "/aVLV38txajXhEy2qNEClPIsDbAH.jpg",
            "release_date": "2022-01-06",
            "title": "Project Gemini",
            "video": false,
            "vote_average": 5.5,
            "vote_count": 98
        }
    ],
    "total_pages": 35518,
    "total_results": 710341
}

InteractorTMDB

import Foundation


protocol AnyInteractor{
    
    var presenter : AnyPresenter? {get set}
    
    func downloadMovies()
    
}

class MovieInteractor : AnyInteractor {
    var presenter : AnyPresenter?
    
    func downloadMovies(){
        
        guard let url = URL(string: "https://api.themoviedb.org/3/movie/popular?api_key=115962553d2044ca5dd8433fb4bc3e29")
        else{
            return
        }
        
        let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
            guard let data = data, error == nil else {
                self?.presenter?.interactorDidDownloadMovie(result:
                        .failure(NetworkError.networkFailed))
                return
            }
            do{
                let movies = try JSONDecoder().decode([Result].self, from: data)
                self?.presenter?.interactorDidDownloadMovie(result: .success(movies))
            }catch{
                self?.presenter?.interactorDidDownloadMovie(result: .failure(NetworkError.parsingFailed))
            }
        }
        task.resume()
    }
    
}

PresenterTMDB

import Foundation

enum NetworkError : Error {
    
    case networkFailed
    case parsingFailed
    
}

protocol AnyPresenter {
    
    var router : AnyRouter? {get set}
    var interactor : AnyInteractor? {get set}
    var view : AnyView? {get set}
    
    func interactorDidDownloadMovie(result: Result<Movies: [Results], Error>)
    
}

class MoviePresenter : AnyPresenter {
    
    var router: AnyRouter?
    
    var interactor : AnyInteractor? {
        didSet{
            interactor?.downloadMovies()
        }
    }
    var view: AnyView?
    
    func interactorDidDownloadMovie(result: Result<Movies: [Results], Error>){
        switch result{
        case .success(let movies):
            view?.update(with: movies)
        case.failure(_):
            view?.update(with: "Intenta más tarde")
        }
    }
}

EntityTMDB

import Foundation


struct Movies: Codable {
    let page: Int
    let results: [Results]
    let totalPages, totalResults: Int

}

struct Results: Codable {
    let adult: Bool
    let backdropPath: String
    let genreIDS: [Int]
    let id: Int
    let originalTitle, overview: String
    let popularity: Double
    let posterPath, releaseDate, title: String
    let video: Bool
    let voteAverage: Double
    let voteCount: Int

}

RouterTMDB

import Foundation
import UIKit

typealias EntryPoint = AnyView & UIViewController

protocol AnyRouter{
    var entry: EntryPoint? {get}
    static func startExecution() -> AnyRouter
}

class MovieRouter : AnyRouter {
    var entry : EntryPoint?
    
    static func startExecution() -> AnyRouter {
        let router = MovieRouter()
        
        var view: AnyView = ViewTMDB() as! AnyView
        var presenter : AnyPresenter = MoviePresenter()
        var interactor : AnyInteractor = MovieInteractor()
        view.presenter = presenter
        
        presenter.view = view
        presenter.router = router
        presenter.interactor = interactor
        interactor.presenter = presenter
        router.entry = view as? EntryPoint
        
        return router
    }
}

I really don't know how to show this JSON response in a tableview using VIPER architecture.

Thanks.

Upvotes: -2

Views: 134

Answers (1)

Duncan C
Duncan C

Reputation: 131481

Take a look at the Codable protocol. For deserializing objects from JSON you'll specifically want the Decodable protocol.

There are simple steps you take to make your structures conform to the Decodable protocol, and then you use an instance of the JSONDecoder class to decode your object.

How to display your data in a table view, using VIPER or not, is a separate question. (And I would suggest running away from VIPER as fast as you can. It isn't a design pattern I recommend.)

Upvotes: -1

Related Questions