Search code examples
iosjsonswiftapijsondecoder

The data couldn’t be read because it isn’t in the correct format. Swift 5


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)
        }
    }

Solution

  • 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" 
        }
    }