Search code examples
swifthttpgithub-api

No value associated with key CodingKeys while trying to get data from GitHub API in Xcode app


So listening to @Larme and @JoakimDanielson (thanks a lot, guys!) I started doing some tasks on URLSessions to actually get the data I am looking for from GitHub API.

The endgame here is to create a mobile GitHub search app for repositories.

I have realised a code from this tutorial: https://blog.devgenius.io/how-to-make-http-requests-with-urlsession-in-swift-4dced0287d40

Using relevant GitHub API URL. My code looks like this:

import UIKit

class Repository: Codable {
    let id: Int
    let owner, name, full_name: String

    enum CodingKeys: String, CodingKey {
        case id = "id"
        case owner, name, full_name
    }

    init(id: Int, owner: String, name: String, fullName: String) {
        self.id = id
        self.owner = owner
        self.name = name
        self.full_name = full_name
    }
}

(...)

        let session = URLSession.shared
                let url = URL(string: "https://api.github.com/search/repositories?q=CoreData&per_page=20")!
                let task = session.dataTask(with: url, completionHandler: { data, response, error in
                    // Check the response
                    print(response)
                    
                    // Check if an error occured
                    if error != nil {
                        // HERE you can manage the error
                        print(error)
                        return
                    }
                    
                    // Serialize the data into an object
                    do {
                        let json = try JSONDecoder().decode(Repository.self, from: data! )
                            //try JSONSerialization.jsonObject(with: data!, options: [])
                        print(json)
                    } catch {
                        print("Error during JSON serialization: \(error.localizedDescription)")
                        print(String(describing:error))
                    }
                    
                })
                task.resume()
        
        
    }
    


} 

The full error text is:

keyNotFound(CodingKeys(stringValue: "id", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"id\", intValue: nil) (\"id\").", underlyingError: nil))

I tried removing some values that had this error but the others still threw the same and I used the coding keys I could find in the GitHub docs: https://docs.github.com/en/rest/reference/search#search-repositories

Please help!


Solution

  • First of all you don't need CodingKeys and the init method.
    Second of all use structs, not classes.

    If you want to decode the repositories you have to start with the root object, the repositories are in the array for key items

    struct Root : Decodable {
        let items : [Repository]
    }
    
    struct Repository: Decodable {
        let id: Int
        let name, fullName: String
        let owner : Owner
    }
    
    struct Owner : Decodable {
        let login : String
    }
    

    Another issue is that owner is also a Dictionary which becomes another struct.

    To get rid of the CodingKeys add the .convertFromSnakeCase strategy which translates full_name into fullName.

    let session = URLSession.shared
    let url = URL(string: "https://api.github.com/search/repositories?q=CoreData&per_page=20")!
    let task = session.dataTask(with: url) { data, response, error in
        // Check the response
        print(response)
        // Check if an error occured
        if let error = error {
            // HERE you can manage the error
            print(error)
            return
        }
        
        // Serialize the data into an object
        do {
            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            let json = try decoder.decode(Root.self, from: data! )
            print(json)
        } catch {
            print("Error during JSON serialization:", error)
        }
    }
    task.resume()