0

I'm trying to build a engine that will take a few pieces of data and parse them through a wikidata query...there are two url session tasks here is my code, but for some reason I can't get the functions to perform the networking to execute...what am I missing?

struct BDayWikiDataManager {
        
    func fetchBDayDataFromWikipedia(numMonth: String, numDay: String) -> (String, String, String) {
        
        var personLabelCode = "no value"
        var occupationLabelCode = "no value"
        var dob = "no value"
        var personName = "no value"
        var occupationName = "no value"
        
        let firstURL = "https://query.wikidata.org/sparql?query=SELECT%20distinct%20%3Fperson%20%3FpersonLabel%20%3Fdob%20%3Foccupation%20%3FoccupationLabel%20%3Fawards%20%3FawardsLabel%0AWHERE%0A{%0A%20%20%3Fperson%20wdt%3AP31%20wd%3AQ5%3B%0A%20%20%20%20%20%20%20%20%20%20wdt%3AP27%20wd%3AQ30%3B%0A%20%20%20%20%20%20%20%20%20%20wdt%3AP569%20%3Fdob%3B%0A%20%20%20%20%20%20%20%20%20%20wdt%3AP166%20%3Fawards%3B%0A%20%20%20%20%20%20%20%20%20%20wdt%3AP106%20%3Foccupation.%0A%20%20OPTIONAL%20{%3Fperson%20wdt%3AP166%20%3Fawards}%0A%20%20FILTER(DAY(%3Fdob)%20%3D%20\(numDay)).%0A%20%20FILTER(MONTH(%3Fdob)%20%3D%20\(numMonth)).%0A%20%20FILTER(YEAR(%3Fdob)%20%3E%3D%201940).%0A%20%20FILTER%20(%3Foccupation%20in%20(%20wd%3AQ33999%2C%20wd%3AQ639669%2C%20wd%3AQ2066131%2C%20wd%3AQ947873%2C%20wd%3AQ15265344%20)%20)%0A%20%20SERVICE%20wikibase%3Alabel%20{%20bd%3AserviceParam%20wikibase%3Alanguage%20%22[AUTO_LANGUAGE]%22.%20}%20%0A}%0ALIMIT%2050&format=json"
        
        performRequestFirstURL(with: firstURL) { (data, error) in
            if error != nil {
                print(error as Any)
            }
            
            personLabelCode = data!.personLabel
            print(personLabelCode)
            occupationLabelCode = data!.occupationLabel
            dob = data!.dob
        }
        
        print(personLabelCode)
        
        let secondUrl = "https://www.wikidata.org/w/api.php?action=wbgetentities&ids=\(personLabelCode)|\(occupationLabelCode)&format=json&props=labels&languages=en"

        let _ = performRequestSecondURL(with: secondUrl, personLabel: personLabelCode, occupationLabel: occupationLabelCode) { (data, error) in
            if error != nil {
                fatalError("performRequestSecondURL failed, error = \(String(describing: error))")
            }
            personName = data!.personName
            occupationName = data!.occupationName
        }

        return (personName, occupationName, dob)
        
        
        

    }
    
    func performRequestFirstURL(with urlString: String, userCompletionHandler: @escaping (FirstURLData?, Error?) -> Void) {

        if let url = URL(string: urlString) {
            URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
                if let data = data {
                    let jsonDecoder = JSONDecoder()
                    do {
                        let parsedJSON = try jsonDecoder.decode(FirstURLIncomingData.self, from: data)
                        print(parsedJSON)
                        let numberOfBindings = parsedJSON.results.bindings.count
                        let randomBindingNumber = Int.random(in: 0...(numberOfBindings - 1))
                        
                        let dob = parsedJSON.results.bindings[randomBindingNumber].dob.value
                        let personLabel = parsedJSON.results.bindings[randomBindingNumber].personLabel.value
                        let occupationLabel = parsedJSON.results.bindings[randomBindingNumber].occupationLabel.value

                        let finalData = FirstURLData(dob: dob, personLabel: personLabel, occupationLabel: occupationLabel)

                        userCompletionHandler(finalData, nil)

                    } catch {
                        print(error)
                        userCompletionHandler(nil,error)
                    }
                }
            })
            .resume()
        }
    }
    
    func performRequestSecondURL(with urlString: String, personLabel: String, occupationLabel: String, userCompletionHandler: @escaping (SecondURLData?, Error?) -> Void) {

        if let url = URL(string: urlString) {
            URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
                if let data = data {
                    let jsonDecoder = JSONDecoder()
                    do {
                        let parsedJSON = try jsonDecoder.decode(SecondURLIncomingData.self, from: data)
                        print(parsedJSON)
                        
                        let name = parsedJSON.entities[personLabel]?.labels.en.value
                        let occupation = parsedJSON.entities[occupationLabel]?.labels.en.value

                        let finalData = SecondURLData(personName: name!, occupationName: occupation!)

                        userCompletionHandler(finalData, nil)

                    } catch {
                        print(error)
                        userCompletionHandler(nil,error)
                    }
                }
            })
            .resume()
        }
    }
    
}
//MARK: - incoming data model - first url

struct FirstURLIncomingData: Codable {
    let results: Results
}

struct Results: Codable {
    
    let bindings: [Bindings]
}

struct Bindings: Codable {
    
    let dob: DOB
    let personLabel: PersonLabel
    let occupationLabel: OccupationLabel
}

struct DOB: Codable {
    let value: String
}

struct PersonLabel: Codable {
    let value: String
}

struct OccupationLabel: Codable {
    let value: String
}

//MARK: - incoming data model - second url

struct SecondURLIncomingData: Decodable {
    
    let entities: [String : Locator]
    
}

struct Locator: Decodable {
    
    let labels: Labels
}

struct Labels: Decodable {
    
    let en: EN
}

struct EN: Decodable {
    
    let value: String
}

//MARK: - model of data for both urls

struct FirstURLData: Decodable {
    
    let dob: String
    let personLabel: String
    let occupationLabel: String

}
struct SecondURLData {
    let personName: String
    let occupationName: String
}

let manager = BDayWikiDataManager()

let data = manager.fetchBDayDataFromWikipedia(numMonth: "8", numDay: "13")

print(data) //prints "no data" for everything, which means the values didnt update

Worth noting: when I go to the url's manually, I get json responses in my browser, so I know the url's are correct...

Benjamin B.
  • 521
  • 7
  • 15
  • You should read more about asynchronous programming. It's a really important topic to understand well. In a nutshell, the data isn't yet available in `fetchBDayDataFromWikipedia` when you return it. That's why asynchronous functions (like `. dataTask` of `URLSession`, and your own `performRequestFirstURL`) have a completion handler as parameter. Same with `personLabelCode` btw, in between two async function calls – New Dev Aug 09 '20 at 21:34
  • ahhh thats the issue, i can only run one url session at a time (or i ought to since one depends on the other)...i'll give this a try and report back (i set something up with dispatch groups so im a bit familiar, but ill do more digging...) – Benjamin B. Aug 09 '20 at 21:38
  • something that is odd is that, if i strip out the second url decoding, the first url decoding doesn't run...it just hangs in playgrounds :/ – Benjamin B. Aug 09 '20 at 21:43

0 Answers0