0

I am having issues trying to get this data. I heard there is a trick. Can anyone create a simple call to view the data from this api? Would truly appreciate it. Been trying for a week. I cant for the life of me get this simple api call to work.

http://api.citybik.es/v2/networks

Model.swift

import Foundation

// MARK: - Welcome
struct Dataset: Codable {
    let networks: [Network]
}

// MARK: - Network
struct Network: Codable {
    let company: [String]
    let href, id: String
    let location: Location
    let name: String
}

// MARK: - Location
struct Location: Codable {
    let city, country: String
    let latitude, longitude: Double
}

Contentview.swift

import SwiftUI

struct ContentView: View {
    
    @State var results = [Network]()
    
    func loadData() {
        guard let url = URL(string: "http://api.citybik.es/v2/networks") else {
            print("Your API end point is Invalid")
            return
        }
        let request = URLRequest(url: url)

        URLSession.shared.dataTask(with: request) { data, response, error in
            if let data = data {
                if let response = try? JSONDecoder().decode([Network].self, from: data) {
                    DispatchQueue.main.async {
                        self.results = response
                    }
                    return
                }
            }
        }.resume()
    }
    
    var body: some View {
        List(results, id: \.name) { item in
            VStack(alignment: .leading) {
                Text("\(item.name)")
            }
        }.onAppear(perform: loadData)
    }
    
    
}

1 Answers1

0

copy the whole of the json from : "https://api.citybik.es/v2/networks" into "https://app.quicktype.io/" and get the (correct) swift data structures from that. Rename "Welcome" to "Response" and use that in your code.

use: "https://api.citybik.es/v2/networks" note the https.

EDIT: In your code:

struct ContentView: View {
    @State var networks = [Network]()
    
    var body: some View {
        List(networks, id: \.id) { network in
            VStack {
                Text(network.name)
                Text(network.location.city)
            }
        }.onAppear(perform: loadData)
    }
    
    func loadData() {
        guard let url = URL(string: "https://api.citybik.es/v2/networks") else {
            print("Your API end point is Invalid")
            return
        }
        let request = URLRequest(url: url)
        URLSession.shared.dataTask(with: request) { data, response, error in
            if let data = data {
                if let response = try? JSONDecoder().decode(Response.self, from: data) {
                    DispatchQueue.main.async {
                        self.networks = response.networks
                    }
                    return
                }
            }
        }.resume()
    }
} 

Once you have all the data structures, and if you are using Swift 5.5 for ios 15 or macos 12, you can use something like this:

struct ContentView: View {
    @State var networks = [Network]()
    
    var body: some View {
        List(networks, id: \.id) { network in
            VStack {
                Text(network.name)
                Text(network.location.city)
            }
        }
        .task {
            let response: Response? = await fetchNetworks()
            if let resp = response {
                networks = resp.networks
            }
        }
    }
    
    func fetchNetworks<T: Decodable>() async -> T? {
        let url = URL(string: "https://api.citybik.es/v2/networks")!
        let request = URLRequest(url: url)
        do {
            let (data, response) = try await URLSession.shared.data(for: request)
            guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
                // throw URLError(.badServerResponse)   //  todo
                print(URLError(.badServerResponse))
                return nil
            }
            let results = try JSONDecoder().decode(T.self, from: data)
            return results
        }
        catch {
            return nil
        }
    }
}