swiftswiftuiswift-playground

What is wrong with this API call parsing JSON data?


This is the current SWIFTUI code I have:

import SwiftUI

struct Holidays: Decodable {
    var date: String
    var localName: String
    var name: String
    var countryCode: String
}

struct HolidaysView: View {
    @State private var holidays = [Holidays]()
    
    var body: some View {
        NavigationView {
            List(holidays, id: \.name) { t in
                VStack(alignment: .leading) {
                    Text(t.date)
                        .font(.headline)
                        .foregroundColor(.cyan)
                    Text(t.name)
                        .font(.body)
                        .foregroundColor(.indigo)
                    Text(t.countryCode)
                        .font(.body)
                        .foregroundColor(.red)
                }
            }
            .navigationTitle("Holidays List")
            .task {
                await fetchHolidaysData()
            }
        }
    }
    
    func fetchHolidaysData() async {
        // create the URL
        guard let url = URL(string: "https://date.nager.at/api/v2/publicholidays/2020/US") else {
            print("THIS URL DOES NOT WORK!")
            return
        }
        
        // fetch the data
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            
            // decode that data
            if let decodedResponse = try? JSONDecoder().decode([Holidays].self, from: data) {
                holidays = decodedResponse
            }
        } catch {
            print("This data is not valid")
        }
    }
}

struct HolidaysView_Previews: PreviewProvider {
    static var previews: some View {
        HolidaysView()
    }
}

The goal of this code is to be able to view the json data using the URL. When I click the navigation title of Holiday List, no data shows up (in contentview). I have tried other API links such as API placeholders for JSON, and they worked. I can't figure out the issue or the difference. I tried AI as well. I do not know what I'm doing wrong, Could it possibly be that I have to use all the variables of data of the API? Or possibly the id? The other apis I used had ids for each section of data so I put

List(holidays, id: \.name) { t in      ```
as 
List(todos, id: \.id) { t in      ```
```, could this be a possible reason?
                       

Solution

  • Here is my working example code that brings together the comment's recommendations. The code lets you achieve your goal, as described The goal of this code is to be able to view the json data using the URL

    struct Holidays: Identifiable, Decodable { // <-- here
        let id = UUID() // <-- here
        
        var date: String
        var localName: String
        var name: String
        var countryCode: String
    
        enum CodingKeys: String, CodingKey {
            case date, localName, name, countryCode  // <-- here no id
        }
    }
    
    // for testing
    struct ContentView: View {
        var body: some View {
            HolidaysView()
        }
    }
    
    struct HolidaysView: View {
        @State private var holidays = [Holidays]()
        
        var body: some View {
            NavigationStack {  // <-- here
                List(holidays) { t in   // <-- here
                    VStack(alignment: .leading) {
                        Text(t.date)
                            .font(.headline)
                            .foregroundColor(.cyan)
                        Text(t.name)
                            .font(.body)
                            .foregroundColor(.indigo)
                        Text(t.countryCode)
                            .font(.body)
                            .foregroundColor(.red)
                    }
                }
                .navigationTitle("Holidays List")
                .task {
                    await fetchHolidaysData()
                }
            }
        }
        
        func fetchHolidaysData() async {
            // create the URL
            guard let url = URL(string: "https://date.nager.at/api/v2/publicholidays/2020/US") else {
                print("THIS URL DOES NOT WORK!")
                return
            }
            // fetch the data
            do {
                let (data, _) = try await URLSession.shared.data(from: url)
                // decode that data
                holidays = try JSONDecoder().decode([Holidays].self, from: data) // <-- here
            } catch {
                print("error: \(error)") // <-- here, important
            }
        }
    }