2

I am trying to decode data from https://swapi.dev/. I get json correctly with response code 200, but the decoder could not read the data because the format is incorrect. I tried it in a lot of different ways. I am trying to get info on peoples.

Here is my code:

Model File

struct people: Codable {
    let count: Int
    let next: String?
    let previous: String?
    let results: [result]
}

struct result: Codable{
    let name: String
    let height: Int
    let mass: Int
    let hair_color: String
    let skin_color: String
    let eye_color: String
    let birth_year: 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
    
}

struct APIError: Codable {
    let detail: String
}

Network Services


typealias OnApiSucces = (people) -> Void
typealias OnApiError = (String) -> Void

struct ApiService {
    static let shared = ApiService()
    
    let URL_BASE = "https://swapi.dev/api"
    let URL_PEOPLE = "/people"
    
    let session = URLSession(configuration: .default)
    

    
    func getResults(onSuccess: @escaping OnApiSucces, onError: @escaping OnApiError) {

        let url = URL(string: "\(URL_BASE)\(URL_PEOPLE)")!
        var request = URLRequest(url: url)
        request.httpMethod = "GET" // GET, PUT, POST, DELETE for some different api
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        let task = session.dataTask(with: request) { (data, response, error) in

                if let error = error {
                    onError(error.localizedDescription)
                    return
                }

                guard let data = data, let response = response as? HTTPURLResponse else {
                    onError("Invalid data or response")
                    return
                }

                do{
                    if response.statusCode == 200 {
                        print("Code is \(response.statusCode)")
                        let results = try JSONDecoder().decode(people.self, from: data)
                        onSuccess(results)
                    } else {
                        let err = try JSONDecoder().decode(APIError.self, from: data)
                        print("Code is \(response.statusCode)")
                        onError(err.detail)
                    }
                }
                catch {
                    onError(error.localizedDescription)
                }

            }
        task.resume()

        }

    }

** Getting data on ViewController**

    func getResults() {
        ApiService.shared.getResults { (people) in
            self.results = people.results
        } onError: { (error) in
            debugPrint(error.description)
        }
    }
drebin96
  • 156
  • 1
  • 13
  • 2
    Tip: paste your resulting JSON into https://app.quicktype.io to get generated model structs – Gereon Jan 30 '21 at 17:15
  • 2
    Never print `error.localizedDescription` in a `JSONDecoder` catch block, the error message is pretty meaningless. Print `error`, it shows you the real comprehensible error. And in JSON everything wrapped in double quotes is `String` even `"123"` or `"false"`. – vadian Jan 30 '21 at 17:17
  • Thanks! I changed to String and it works now. – drebin96 Jan 30 '21 at 17:41

1 Answers1

1

First, your data can't be read because height and mass are represented as String in the Star Wars API, while you represent them as Int in your Codable struct.

Also, try adding CodingKeys to your Codable struct so your struct adheres to naming conventions (specifically regarding your attribute_color variants) e.g.

struct result: Codable{
    let name: String
    let height: String
    let mass: String
    let hairColor: String  // changed from hair_color
    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
    enums CodingKeys: String, CodingKey {
      case name = "name"
      case height = "height"
      case mass = "mass"
      case hairColor = "hair_color"
      case skinColor = "skin_color"
      case eyeColor = "eye_color"
      case birthYear = "birth_year"
      case gender = "gender"
      case homeworld = "homeworld"
      case films = "films"
      case species = "species"
      case vehicles = "vehicles"
      case starships = "starships"
      case created = "created"
      case edited = "edited"
      case url = "url" 
    }
}
nonamorando
  • 1,556
  • 2
  • 14
  • 33