Loop over an API request updating the URL

1.4k views Asked by At

I am working with the GoogleMaps API, this returns 20 nearby locations and up to 60 locations can be returned. The locations are returned with a nextPageToken which allows you to GET the next page of results (20 per page). I am trying to loop through the API to enable myself to get all the locations available but am having difficulty: func getAllNearbyLocations(url: URL) {

I am using Alamofire to return the API request (I have also tried using URLSessions)

First I put together a function which returns the json dictionary in the completion block

// This function returns the JSON from a specific URL
func getJsonFromURL(url: URL, completionHandler: @escaping (NSDictionary) -> ()) {

    Alamofire.request(url).responseJSON { response in

        let json = response.result.value as! NSDictionary

        completionHandler(json)
    }
}

Next we have a getNearByLocation function which we initialise with a url. As you can see we return the results, add them to an array, check if we have the max number of results (60) or don't have a nextPageToken any more. If either of these are false we create the new URL and fire the function we are currently in again. The loop finishes when we return all the new locations.

func getAllNearbyLocations(url: URL) {
    self.getJsonFromURL(url: url) { (dictionary) in

        let newLocations: NSArray = dictionary.value(forKey: "results") as! NSArray
        self.locations.addObjects(from: newLocations as! [Any])

        if self.locations.count >= 60 {
            self.sendNewLocations(locations: self.locations)
        }
        else {

            // We want to now update the URL we are using and search again
            if let newPageToken = dictionary["next_page_token"] {

                let newURL = self.rootSearchURL + "&pagetoken=" + (newPageToken as! String)
                let url = URL(string: newURL)

                // We want to get our current URL and remove the last characters from it    
                self.getAllNearbyLocations(url: url!)
            }
            else {

                // If we have no more pages then we return what we have
                self.sendNewLocations(locations: self.locations)
            }
        }
    }
}

The strange thing is when I test the code with breakpoints it returns as expected. It loops through the function, adds all the new locations and returns. When I run it in realtime the returned dictionary doesn't return properly (doesn't contain the locations or next page token) and so my function only returns the first 20 locations.

I have used API requests before but never so close in succession. I feel that it is a catch 22 as I can't know the new pageToken until I have called the request and as soon as I have returned the request I want to call the request with that token immediately.

1

There are 1 answers

0
Vini App On BEST ANSWER

As per the Documentation,

There is a short delay between when a next_page_token is issued, and when it will become valid. Requesting the next page before it is available will return an INVALID_REQUEST response. Retrying the request with the same next_page_token will return the next page of results.

Try to check what you are getting when you are retrieving data with new_page_token

Try to call like this :

let newURL = self.rootSearchURL + "&pagetoken=" + (newPageToken as! String)
let url = URL(string: newURL)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
    // We want to get our current URL and remove the last characters from it    
    self.getAllNearbyLocations(url: url!)
}