martincarlin87
martincarlin87

Reputation: 11042

Decode Nested JSON REST Api Response in to Array of Structs

I am trying to parse the response of https://swapi.dev/api/people/ in to a List but I can't seem to get it work due to the nested response structure instead of a flat response.

This is my ContentView:

struct ContentView: View {

    private let charactersURL = URL(string: "https://swapi.dev/api/people/")!

    @State private var characters: [Character] = []


    var body: some View {

        NavigationView {

            VStack {

                List {
                    ForEach(characters, id: \.self) { character in
                        NavigationLink(destination: CharacterView(character: character)) {
                            Text(character.name)
                        }
                    }
                }
                .onAppear(perform: loadCharacter)
            }
            .navigationBarTitle("Swapi Api Client")

        }

    }

    private func loadCharacter() {

        let request = URLRequest(url: charactersURL)
        URLSession.shared.dataTask(with: request) { data, response, error in
            if let data = data {
                if let charactersResponse = try? JSONDecoder().decode([Character].self, from: data.results) {
                    withAnimation {
                        self.characters = charactersResponse.results
                    }
                }
            }

        }.resume()
    }

}

I have a CharactersResponse struct:

struct CharactersResponse {
    let count: Int
    let next: String
    let previous: NSNull
    let results: [Character]
}

and a Character struct:

struct Character: Decodable, Hashable {
    let name: String
    let height: Int
    let mass: String
    let hairColor: String
    let skinColor: String
    let eyeColor: String
    let birthYear: String
    let gender: String
    let homeworld: String
    let films: [String]
    let species: [String]
    let vehicles : [String]
    let starships: [String]
    let created: String
    let edited: String
    let url: String
}

The error I get is Value of type 'Data' has no member 'results' but I'm not sure how to fix it so that the CharactersResponse results are parsed in to an array of Character structs.

enter image description here

Upvotes: 1

Views: 258

Answers (1)

vadian
vadian

Reputation: 285039

You are mixing up the raw data and the deserialized structs

Replace

if let charactersResponse = try? JSONDecoder().decode([Character].self, from: data.results) { ...

with

if let charactersResponse = try? JSONDecoder().decode(CharactersResponse.self, from: data) { ...

And adopt Decodable in CharactersResponse

struct CharactersResponse : Decodable { ...

You might also replace NSNull with an optional of the expected type


Never try? in a JSONDecoder context. catch a potential error and print it.

do {   
    let charactersResponse = try JSONDecoder().decode(CharactersResponse.self, from: data) { ...

} catch { print(error) }

Upvotes: 2

Related Questions