jsonlistswiftuidecode

Difficulty in accessing json data from jsonbin


I use code that downloads and displays json data from a number of different public json sites such as Apple Music and jsonplaceholder. I have some test data in a bin at jsonbin.io. When I use the same code I cannot get the data to populate a list in SwiftUI. The test data is a public json and is non-sensitive. Any idea what I am doing wrong?

struct Facility: Codable, Identifiable {
var id: String
var facilityName: String
}


struct FacilityView: View {


@State private var facilities = [Facility]()

var body: some View {
    NavigationView {
    List(facilities, id: \.id) {item in
        VStack {
            Text(item.id)
                .font(.headline)
            Text(item.facilityName)
            }
        }
    .navigationTitle("Facilities")
    
    .task {
        await fetchData()
    }
}
}

func fetchData() async {
    guard let url = URL(string: "https://api.jsonbin.io/v3/b/66130dbead19ca34f85689bc") else {
        print("URL does not work")
        return
        }
    do {
        let (data, _) = try await URLSession.shared.data( from: url)

        if let decodedResponse = try? JSONDecoder().decode([Facility].self, from: data) {
            facilities = decodedResponse
        }
    } catch {
        print("Data not valid")
    }
}
}

#Preview {
FacilityView()
}

Solution

  • The response you get from the server is not an array [Facility]. So trying to decode this gives you an error that you should print, as shown in the example code.

    Try this approach using a set of models that match the json data.

    Note, don't use try? and print the actual error print("Data not valid \(error)")

    struct ServerResponse: Codable {
        let record: [Facility]
        let metadata: Metadata
    }
    
    struct Metadata: Codable {
        let id: String
        let metaPrivate: Bool
        let createdAt: String
    
        enum CodingKeys: String, CodingKey {
            case id
            case metaPrivate = "private"
            case createdAt
        }
    }
    
    struct Facility: Codable, Identifiable {
        var id: String
        var facilityName: String
    }
    
    struct ContentView: View {
        var body: some View {
            FacilityView()
        }
    }
    
    struct FacilityView: View {
        @State private var facilities = [Facility]()
        
        var body: some View {
            NavigationView {
                List(facilities) { item in
                    VStack {
                        Text(item.id).font(.headline)
                        Text(item.facilityName)
                    }
                }
                .navigationTitle("Facilities")
                .task {
                    await fetchData()
                }
            }
        }
        
        func fetchData() async {
            guard let url = URL(string: "https://api.jsonbin.io/v3/b/66130dbead19ca34f85689bc") else {
                print("URL does not work")
                return
            }
            do {
                let (data, _) = try await URLSession.shared.data( from: url)
                let decodedResponse = try JSONDecoder().decode(ServerResponse.self, from: data)
                facilities = decodedResponse.record
            } catch {
                print("Data not valid \(error)") // <--- important
            }
        }
    }