Search code examples
swiftalamofire

How to pass Decodable.protocol as a function parameter from structs property?


I have a struct Endpoint

struct Endpoint {
    let responseDecodable: Decodable.Type
    let path: String
    let queryItems: [URLQueryItem]
}

which is used to construct different api requests using Alamofire:

func fetchData(_ endpoint: Endpoint) {
        AF.request(endpoint.url!).responseDecodable(of: endpoint.responseDecodable) { response in
            
        }
    }
extension Endpoint {
    static func getUser(by id: Int) -> Endpoint {
        return Endpoint(
            responseDecodable: UsersGet.self,
            path: ... ,
            queryItems: ... )
    }
    static func getFriends(by user: User) -> Endpoint {
        return Endpoint(
            responseDecodable: FriendsGet.self,
            path: ... ,
            queryItems: ... )
    }

The problem is, different endpoint requests give different JSON objects, and I need to specify that type in responseDecodable(of: Decodable.Protocol)

But AF.request in func fetchData gives me an error: Cannot convert value of type 'Decodable.Type' to expected argument type 'T.Type' How do I pass that Decodable.Protocol from Endpoint without making a generic struct?


Solution

  • Looking back I see that was a silly question but hey
    Generic struct that returns type in the endpoint constructor solves the problem.

    struct Endpoint<T> where T: Decodable {
        let path: String
        let queryItems: [URLQueryItem]
    }
    
    extension Endpoint {
        static func getUser(by id: Int) -> Endpoint<UsersGet> {
            return Endpoint<UsersGet>(
                path: ... ,
                queryItems: ... )
            )
        }
        // same for other endpoints
    }
    

    And the fetchData function used like this with generic parameter that is automatically inferred (that's what I wanted)

    func fetchData<T: Decodable>(_ endpoint: Endpoint<T>, completion: @escaping (DataResponse<T, AFError>) -> Void) {
        AF.request(endpoint.url!).responseDecodable(completionHandler: completion)
    }
    
    fetchData(.getFriends(by: user)) { response in
        // ... 
    }