Search code examples
jsonswiftcombineurlsessiondecodable

Swift URLSession and Combine json array decode fails


Well guys like the title says i have on a response service call an JSON array and i cant find the way to decode with Combine: URLSession.shared.dataTaskPublisher

Service Response: https://codebeautify.org/alleditor/y228809f7

My Request Code:

public func getGasStationDiscounts(requestModel: GasStationDiscountsRequestDomainModel) -> CiMAObservable<GasStationDiscountsDomainModel> {
    guard let url = URL(string: RepositoryConstants.baseURL + String(format: RepositoryConstants.EndPoints.gasStationDiscounts, requestModel.gasStationID)) else {
        return Fail(error: NSError(domain: "URL Invalid", code: 001, userInfo: nil)).eraseToAnyPublisher()
    }
    
    var urlRequest = URLRequest(url: url)
    urlRequest.httpMethod = "GET"
    urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
    urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
    
    return URLSession.shared.dataTaskPublisher(for: urlRequest)
        .map(\.data)
        .decode(type: GasStationDiscountsDataModel.self, decoder: JSONDecoder())
        .map { model -> GasStationDiscountsDomainModel in
            model.parseToDomainModel()
        }.eraseToAnyPublisher()
}

Decodable File: https://codebeautify.org/alleditor/y2296aefe

So resuming, my problem is on trying to decode it because its an Array, on my project i'm working with diferent layers like Data, Domain and the Presentation (don't ask about architecture cuz is a new one, CiMA on GitHub) its a Hybrid Viper arch.

Thanks in advance!

EDITED: SOLVED! So finally i found a Solution which don't destroy my architecture. So here the small changes on decodable Files: https://codebeautify.org/alleditor/y22ad811e

and the last changes on the Request:

    public func getGasStationDiscounts(requestModel: GasStationDiscountsRequestDomainModel) -> CiMAObservable<GasStationDiscountsDomainModel> {
    guard let url = URL(string: RepositoryConstants.baseURL + String(format: RepositoryConstants.EndPoints.gasStationDiscounts, requestModel.gasStationID)) else {
        return Fail(error: NSError(domain: "URL Invalid", code: 001, userInfo: nil)).eraseToAnyPublisher()
    }
    
    var urlRequest = URLRequest(url: url)
    urlRequest.httpMethod = "GET"
    urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
    urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
    
    return URLSession.shared.dataTaskPublisher(for: urlRequest)
        .map(\.data)
        .decode(type: [GasStationDiscountsDataModel].self, decoder: JSONDecoder())
        .map { model -> GasStationDiscountsDomainModel in
            let stationDiscountsDomainModel = model.map { model -> StationDiscountDomainModel in
                model.parseToDomainModel()
            }
            return GasStationDiscountsDomainModel(stationDiscounts: stationDiscountsDomainModel)
        }
        .mapError { error in
            print(error.localizedDescription)
            return error
        }.eraseToAnyPublisher()
}

Solution

  • The response seems to be an array. There is no top level element. Use:

    .decode(type: [StationDiscountDataModel].self, decoder: JSONDecoder())