DRN
DRN

Reputation: 155

Swift combine get custom objects from AnyPublisher

I'm trying to fetch 'Post' objects from the API with AnyPublisher, but I'm unable to get the result. How can we achieve result from AnyPublisher<[Post], Error>

Here is my code,


import UIKit
import Combine

struct Post: Decodable{
    var id: Int
    var userId: Int
    var body: String
    var title: String

}

protocol API {
    var baseUrl: String { get }
    var path: URL { get }
}

enum PostService: API {

    var baseUrl : String { "https://jsonplaceholder.typicode.com" }
    case all
    var path: URL {
        switch self {
        case .all:
            return URL(string: baseUrl + "/posts")!
        }
    }

    func fetch(from url: URL) -> AnyPublisher<[Post], Error> {
        return URLSession.shared
            .dataTaskPublisher(for: url)
            .mapError { $0 as Error }
            .map(\.data)
            .decode(type: [Post].self, decoder: JSONDecoder())
            .eraseToAnyPublisher()

    }
}

PostService.fetch(.all)  
// how to get all posts here

Upvotes: 1

Views: 4811

Answers (1)

Alex Antonyuk
Alex Antonyuk

Reputation: 171

Your code is wrong, at least the way you are calling it, I assume it should be something like this

enum PostService: API {

    var baseUrl : String { "https://jsonplaceholder.typicode.com" }
    case all
    var path: URL {
        switch self {
        case .all:
            return URL(string: baseUrl + "/posts")!
        }
    }

    func fetch() -> AnyPublisher<[Post], Error> {
        return URLSession.shared
            .dataTaskPublisher(for: path)
            .mapError { $0 as Error }
            .map(\.data)
            .decode(type: [Post].self, decoder: JSONDecoder())
            .eraseToAnyPublisher()

    }
}

then you would be able to subscribe to it like so

PostService.all.fetch().sink { completion in

} receiveValue: { posts in

}

If you really want to keep call syntax the way you wrote it, you would need to update your code like this

enum PostService: API {

    var baseUrl : String { "https://jsonplaceholder.typicode.com" }
    case all
    var path: URL {
        switch self {
        case .all:
            return URL(string: baseUrl + "/posts")!
        }
    }

    static func fetch(from url: Self) -> AnyPublisher<[Post], Error> {
        return URLSession.shared
            .dataTaskPublisher(for: url.path)
            .mapError { $0 as Error }
            .map(\.data)
            .decode(type: [Post].self, decoder: JSONDecoder())
            .eraseToAnyPublisher()

    }
}

note the fetch method is static now

Upvotes: 3

Related Questions