getRequestToken String
getSessionID String
getUserID Int
getMoviesForSearchString
getFavoriteMovies
postToFavorites
getWatchlistMoviews
postToWatchlist
Month: June 2017
Post request
client -> data -> server
func performThisclosure(closure: (void) -> void){ closure() }
func justDoIt(it: (Void) -> Void){ it() }
justDo { print("print me now!") }
var somethingToDo: (Void) -> Void = {} func doItLater(it: @escaping (void) -> Void){ somethingToDo = it }
subdomain
an extension to a domain name used to organize resources together
https://api.themoviedb.org/3/authentication/token/new?api_key=ENTER_YOUR_API_KEY_HERE
extension AppDelegate { func tmdbURLFromParameters{_ paramters: [String:AnyObject], withPathExtension: String? = nil) -> URL { var components = URLComponents() components.scheme = Constants.TMDB.ApiScheme components.host = Constants.TMDB.ApiHost components.path = Constants.TMDB.ApiPath + (withPathExtension ?? "") components.queryItems = [URLQueryItem]() for (key, value) in parameters { let queryUtem = URLQueryItem(name: key, value: "\(value)") components.queryItems!.append(queryItem) } return components.url! }} }
private func getRequestToken() { /* TASK: Get a request token, then store it (appDelegate.requestToken) and login with the token */ /* 1. Set the parameters */ let methodParameters = [ Constants.TMDBParameterKeys.ApiKey: Constants.TMDBParameterValues.ApiKey ] /* 2/3. Build the URL, Configure the request */ let request = URLRequest(url: appDelegate.tmdbURLFromParameters(methodParameters as [String:AnyObject], withPathExtension: "/authentication/token/new")) /* 4. Make the request */ let task = appDelegate.sharedSession.dataTask(with: request) { (data, response, error) in // if an error occurs, print it and re-enable the UI func displayError(_ error: String) { print(error) performUIUpdatesOnMain { self.setUIEnabled(true) self.debugTextLabel.text = "Login Failed (Request Token)." } } /* GUARD: Was there an error? */ guard (error == nil) else { displayError("There was an error with your request: \(error)") return } /* GUARD: Did we get a successful 2XX response? */ guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 else { displayError("Your request returned a status code other than 2xx!") return } /* GUARD: Was there any data returned? */ guard let data = data else { displayError("No data was returned by the request!") return } /* 5. Parse the data */ let parsedResult: [String:AnyObject]! do { parsedResult = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:AnyObject] } catch { displayError("Could not parse the data as JSON: '\(data)'") return } /* GUARD: Did TheMovieDB return an error? */ if let _ = parsedResult[Constants.TMDBResponseKeys.StatusCode] as? Int { displayError("TheMovieDB returned an error. See the '\(Constants.TMDBResponseKeys.StatusCode)' and '\(Constants.TMDBResponseKeys.StatusMessage)' in \(parsedResult)") return } /* GUARD: Is the "request_token" key in parsedResult? */ guard let requestToken = parsedResult[Constants.TMDBResponseKeys.RequestToken] as? String else { displayError("Cannot find key '\(Constants.TMDBResponseKeys.RequestToken)' in \(parsedResult)") return } /* 6. Use the data! */ self.appDelegate.requestToken = requestToken self.loginWithToken(self.appDelegate.requestToken!) } /* 7. Start the request */ task.resume() }
Accessing User
Personal and Private == “User” Data
sometimes all the data is ‘user’ data
Anyone can access == “Anonymous” Data
(call a method using API key and arguments)
Authentication — ensuring someone’s identity (i.e. “we’ve confirmed this user is indeed Jarrod Parkes”)
Authorization — providing someone access to something (i.e. “this user is allowed to post ratings for movies”)
Which methods to use?
get a list of movies by genre? /genre/{$id$}/moview
get a list of our favorite movies? /account/{$id$}/favorite/movies
add or remove a movie from our favorites list? /account/{id}/favorite
Movie DB API
https://developers.themoviedb.org/3/getting-started
Getting strated
1. Partially implemented so we can focus on networking
2. Uses the AppDelegate like singleton
3. Each HTTP request is broken into 7 steps
Pieces of a URL
http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo
1.query, 2.hostname, 3.scheme, 4.path
https://api.flickr.com/service/rest?safe_search=1&extras=url_m&bbox=1.29,47.85,3.29,49.85&api_key=[YourApiKey]&method=flickr.photo.search&format=json&nojsoncallback=1
Swift equivalent for MIN and MAX macros
https://stackoverflow.com/questions/24186648/swift-equivalent-for-min-and-max-macros
NSURLSession, NSURLRequest, NSURLSessionDataTask
Make request -> Parse the JSON returned -> Determine # of pages of results -> Generate random # in that range -> Make a second request -> Get the random photo from random page of results
private func displayImageFromFlickrBySearch(_ methodParameters: [String: AnyObject], withPageNumber: Int){ var methodParametersWithPageNumber = methodParameters methodParametersWithPageNumber[Constants.FlickrParmeterKeys.Page] = withPageNumber as AnyObject? }
Search Method
48.85N, 2.29E
LatLon.net
48.85
NSURLQueryItem(name: “name”,value:”value”)
public var queryItems:[NSURLQueryItem]?
import Foundation var components = URLComponents() components.scheme = "https" components.host = "api.flickr.com" components.path = "/services/rest" components.queryItems = [URLQueryItem]() let queryItem1 = URLQueryItem(name: "method", value: "flickr.photo.search") let queryItem2 = URLQueryItem(name: "api_key", value: "1234") let queryItem3 = URLQueryItem(name: "text", value: "purple") components.queryItems!.append(queryItem1) components.queryItems!.append(queryItem1) components.queryItems!.append(queryItem1) print(components.url!)
Achievement Solution
var matchmakingIds: [Int] = [] for categoryDictionary in categoryDictionaries { if let title = categoryDictionary["title"] as? String, title == "Matchmaking"{ guard let children = categoryDictionary["children"] as? [NSDictionary] else { print("Cannot find key 'children' in \(categoryDictionary)") return } for child in children { guard let categoryId = child["categoryId"] as? Int else { print("Cannot find key 'categoryId' in \(child)") return } matchmakingIds.append(categoryId) } } }
JSON Example
{ "first": "John", "last": "Smith", "age": 35, "employeed": true, "hobbies": [ "fishing", "bowling", "programming" ], "relatives": { "mother": "Susan", "father": "Eric", "siblings": null } }
Here is a simple mapping JSON types to Swift types(JSON –> Swift)
null ==> nil
Number ==> Int, Float, Double
String ==> Bool
Array ==> [AnyObject]
Object ==> [String:AnyObject]
guard let arrayOfPhotoDictionaries = photosDictionary["photo"] as? [[String:AnyObject]] else { print("Cannot find key 'photo' in \(photosDictionary)") return }
for (index, photo) in arrayOfPhotoDictionaries.enumerated(){ print("\(index):\(photo)") }
let rarities = ["Free", "Common"] for rarity in rarities { numCostForRarityItemsDictionary[rarity] = 0 sumCostForRarityDictionary[rarity] = 0 } guard let rarityForCard = cardDictionary["rarity"] as? String else { print("Cannot find key 'rarityForCard' in \(cardDictionary)") return } numCostForRarityItemsDictionary[rarityForCard]! += 1 sumCostForRarityDictionary[rarityForCard]! += manaCost guard let arrayOfBasicSetCardDictionaries = parsedHearthstoneJSON["Basic"] as? [[String:AnyObject]] else { print("cannot find key 'basic" in \(parsedHearthstoneJSON)") return }
Parsing JSON
keyX, valueX: numbers, array, even dictionary
Parsing JSON
1. get the raw JSON data
2. parse the JSON data into a funcation object
3. grab the data from the foundation object
if let photosDictionary = parseResult[Constants.FlickrResponseKeys.Photos] as? [String: AnyObject], photoArray = photosDictonary[Constants.FlickrResponseKeys.Photo] as? [String:AnyObject]{ let randomPhotoIndex = Int(ar:4random_uniform(UInt32(photoArray.count))) }
private func getImageFromFlickr(){ let methodParameters = [ Constants.FlickrParameterKeys.Method: Constants.FlickrParameterValues.GalleryPhotosMethod, Constants.FlickrParameterKeys.APIKey: Constants.FlickrParameterValues.APIKey, Constants.FlickrParameterKeys.GalleryID: Constants.FlickrParameterValues.GalleryID, Constants.FlickrParameterKeys.Extras: Constants.FlickrParameterValues.MediumURL, Constants.FlickrParameterKeys.Format: Constants.FlickrParameterValues.ResponseFormat, Constants.FlickrParameterKeys.NoJSONCallback: Constants.FlickrParameterValues.DisableJSONCallback ] let session = URLSession.shared lel urlString = Constants.Flickr.APIBaseURL + escapedParameters(methodParameters as [String:AnyObject]) let url = URL(string: urlString)! let request = URLRequest(url: url) let task = session.dataTask(with: request){ (data, response, error) in func displayError(_ error: String){ print(error) print("URL at time of error: \(url)") performUIUpdatesOnMain{ self.setUIEnabled(true) } guard(error == nil) else { displayError("There was an error with your request: \(error)") return } guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode displayError("Your request returned a status code other than 2xx!") return } guard let data = data else { displayError("No data was returned by the request!") return } let parsedResult: [String:AnyObject]! do { parsedResult = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:AnyObject]) } catch { displayError("Could not parse the data as JSON:'\(data)'") return } guard let stat = parsedResult[Constants.FlickrResponseKeys.Status] as ? String, stat == Constants.FlickrResponseValues.OKStatus else { displayError("Cannot find keys '\(Constants.FlickrResponseKeys.Photos)'") return } let randomPhotoIndex = Int(arc4random_uniform(UInt32(photoArray.count))) let photoDictionary = photoArray[randomPhotoIndex] as [String:AnyObject] let photoIitle = photoDictionary[Constants.FlickrResponseKeys.Title]as? String guard let imageUrlString = photoDictionary[Constants.FlickrResponseKeys.MediumURL] as? String else { displayError("Cannot find key '\(Constants.FlickrResponseKeys.MediumURL)' in \(photoDictionary)") return } let imageURL = URL(string: imageUrlString) if let imageData = try? Data(contentsOf: imageURL!){ performUIUpdatesOnMain { self.setUIEnabled(true) self.photoImageView.image = UIImage(data: imageDAta) self.photoTitleLabel.text = photoTitle ?? "(Untitled)" } } else { displayError("Image does not exist at \(imageURL)") } task.resume()
Basics of Serialization
if let data = data { let parsedResult: AnyObject! do { parsedResult = try NSJSONSerialization.JSONObjectWithData(data, options: AllowFraments) } catch { displayError("could not parse the data as JSON: '\(data)'") return } }