Last active
May 9, 2021 15:45
Revisions
-
StewartLynch revised this gist
May 9, 2021 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -110,6 +110,7 @@ func printAllTitles(completion: @escaping ([Items]) -> Void) { if nextPageToken != nil { // Here is where I am stuck. I need to keep calling getAllItems until nextPageToken is no longer nil so that I can append all of the items to the allItems array and then execute the completion // I am forcing completion here so that you can see that I get the first 20 in the set // NOTE ****** If I don't complete here, I am in an infinite loop and my daily API quota exceeds and I can't work on it again until the next day completion(foundItems) } else { completion(foundItems) -
StewartLynch created this gist
May 9, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,125 @@ import Foundation // Here is the codable model that I am trying to decode the feed into struct Feed: Codable { let items: [Items] let pageInfo: PageInfo let nextPageToken: String? } struct PageInfo: Codable { let totalResults: Int let resultsPerPage: Int } struct Items: Codable, Identifiable { struct Snippet: Codable { struct Thumbnails: Codable { struct Default: Codable { let url: URL } let `default`: Default? } struct ResourceId: Codable { let videoId: String } let publishedAt: Date let title: String let description: String let thumbnails: Thumbnails let resourceId: ResourceId? let channelId: String? } let id: String let snippet: Snippet } // Here is a sample endpoint. I have specified maxResults here as 20, because I know that there are 50items in this playlist and so there will be pagination involved meaning that for the first 4 requests, the Feed object's nextPageToken will not be nil let endpoint = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet%2CcontentDetails&maxResults=20&playlistId=PLBn01m5Vbs4C8jeAmLZxk9kZ59lYtxnHW&key=AIzaSyAfF93xIFQEVYXjci2P3VYdhIWNFG9n7cw" // This is what I currently use for my APIServce to make a request to get the JSON enum APIService { struct ErrorType: Identifiable { let id = UUID() let error: APIError } public enum APIError: Error { case error(_ errorString: String) } public static func getJSON<T: Decodable>(urlString: String, dateDecodingStategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys, completion: @escaping (Result<T,APIError>) -> Void) { guard let url = URL(string: urlString) else { completion(.failure(.error("Invalid URL"))) return } let request = URLRequest(url: url) URLSession.shared.dataTask(with: request) { (data, response, error) in if let error = error { completion(.failure(.error("URLError: \(error.localizedDescription)"))) return } guard let data = data else { completion(.failure(.error("Error: Data is corrupt."))) return } let decoder = JSONDecoder() decoder.dateDecodingStrategy = dateDecodingStategy decoder.keyDecodingStrategy = keyDecodingStrategy guard let decodedData = try? decoder.decode(T.self, from: data) else { completion(.failure(.error("Error: decoding data."))) return } completion(.success(decodedData)) }.resume() } } // So, when when I want to retrieve the data, I do this. var allItems = [Items]() // Here is a function that I use to retrieve the items and populate the allItems array func getAllItems(nextPageToken:String? = nil, completion: @escaping (Feed) -> Void) { var urlString = endpoint if let nextPageToken = nextPageToken { urlString = endpoint + "&pageToken=\(nextPageToken)" } APIService.getJSON(urlString: urlString,dateDecodingStategy: .iso8601) { (result: Result<Feed, APIService.APIError>) in switch result { case .success(let feed): completion(feed) case .failure(let error): print(error.localizedDescription) } } } // Example processing of retrieved items func printAllTitles(completion: @escaping ([Items]) -> Void) { var foundItems = [Items]() getAllItems { feed in foundItems += feed.items let nextPageToken = feed.nextPageToken if nextPageToken != nil { // Here is where I am stuck. I need to keep calling getAllItems until nextPageToken is no longer nil so that I can append all of the items to the allItems array and then execute the completion // I am forcing completion here so that you can see that I get the first 20 in the set completion(foundItems) } else { completion(foundItems) } } } printAllTitles { items in allItems = items for item in allItems { print(item.snippet.title) } }