Using the new Instagram Basic Display API in Xcode using UIStoryboard:
Learn about URLSession, using the new Instagram Basic Display API, and UIStoryboard in this Swift 5 iOS Tutorial.
Version:-
Swift 5, iOS 13, Xcode 11
This is a post by Tushar Gusain, an Android/iOS developer.
Social networks are an indispensable part of our daily lives. Not only do we access social networks via websites like twitter.com, facebook.com or instagram.com, but we also find social features in apps, websites, blogs, video games, and more.
Integrating some social features into your apps can increase the virality of your app, they can help you identify and retain customers, and can add value to your app.
Before the update starting October 15, 2019, https://api.instagram.com/v1 was used to get the Instagram User Access Token, Permissions and Data from an Instagram user. After that the api was moved and is now owned by Facebook. You can find more information about the deprecation here: https://www.instagram.com/developer/ .
Keep reading to know how simple it is to integrate the new Instagram API in your app.
About the updated Instagram Api
Facebook provides two apis to integrate into your app to get the instagram features inside your app.The first one is Instagram Graph API ,which can allow the users of our app to access data in their Instagram Business and Instagram Creator accounts. It is categorized under the Business Apis provided by Facebook.
The second one (which we will be using in this tutorial) is the Instagram Basic Display API. It is categorized under the Consumer Api provided by Facebook , it’ll allow the users of our app to get basic profile information, photos, and videos from their Instagram accounts.This API is intended for non-Business and non-Creator Instagram users.
As we will be using a non-Business and non-Creator account in this tutorial, therefore we are using the Instagram Basic Display Api.
For more information on the Instagram Apis follow this link: https://developers.facebook.com/docs/instagram
Getting started
Before we start you should have your own Facebook developer account , you can create one here : Facebook Developer Account .
Step 1: Create a Facebook App
Go to developers.facebook.com, click My Apps, and create a new app. Once you have created the app and are in the App Dashboard, navigate to Settings > Basic, scroll to the bottom of page, and click Add Platform.
Choose iOS, add your iOS Bundle ID and Shared Secret, and save your changes.
To get your Bundle ID click on your project in Xcode, choose your Target, then click on General, you’ll find your Bundle ID inside Identity > Display Name.
For your Shared Secret copy your App Secret and paste it inside Shared Secret.
Step 2: Configure Instagram Basic Display
Click Products, locate the Instagram product, and click Set Up to add it to your app.
Click Basic Display, scroll to the bottom of the page, then click Create New App.
Now, inside Display Name field, enter the name of the Facebook app you just created.
Next in Valid OAuth Redirect URIs, enter your website’s URL or any other website’s URL. Normally this would be a dedicated URI that can capture redirect query string parameters, but for this tutorial you can use any website’s URL.
For example: https://www.google.com/
Copy the complete URL somewhere since you will need it in later steps to get authorization codes and access tokens.
In Deauthorize Callback URL, enter the copied URL again. Eventually you will have to change this to a URL that can handle deauthorization notifications, but for the purposes of this tutorial, you can re-use the above copied URL.
Do the same forData Deletion Request Callback URL.
Skip the App Review section for now since you will not be switching the app to Live Mode during the tutorial.
Step 3: Add an Instagram Test User
Navigate to Roles > Roles and scroll down to the Instagram Testers section. Click Add Instagram Testers and enter your Instagram account’s username and send the invitation.
Open a new web browser and go to www.instagram.com and sign into your Instagram account that you just invited. Navigate to (Profile Icon) > Edit Profile > Apps and Websites > Tester Invites and accept the invitation.
Note:- Do not add any profile in the Testers section, as we are not testing the facebook app here.
Your Instagram account is now eligible to be accessed by your Facebook app while it is in Development Mode.
Setting up your Xcode project
Step 1: Create an Xcode project
Open Xcode, click on New project, then select Single View App and click Next.
Now, Enter the name of your App in the Product Name field, then, select Swift as Language and Storyboard as User Interface.
After that click on Next.
Step 2: Create the InstagramApi class
Now, create a new Swift file, name it InstagramApi, then inside the file declare a class InstagramApi, this class will be responsible for handling api requests. Getting the oauth token, fetching your feed, media etc.
class InstagramApi { static let shared = InstagramApi() private let instagramAppID = “{your-instagram-app-id}” private let redirectURIURLEncoded = “https%3A%2F%2Fwww.hotcocoasoftware.com%2F" private let redirectURI = “https://www.hotcocoasoftware.com/" private let app_secret = “{your-app-secret}” private let boundary = “boundary=\(NSUUID().uuidString)” private init () {}}
Now, copy and paste the above code inside your InstagramApi class.
Replace {your-instagram-app-id} with the instagram app id in your facebook app.
(Note:- Do not confuse instagram app id with facebook app id, your instagram app id is given inside Products > Instagram> Basic Display > Instagram App ID )
Then , replace {your-app-secret} with your Instagram app secret.
Here, I have used https://www.hotcocoasoftware.com/ as the redirect URI , you can use any URI you want for this tutorial.
For example, if you use https://www.google.com/ as redirectURI your then change the redirectURIURLEncoded’s value to “https%3A%2F%2Fwww.google.com%2F".
Now, declare the below enums inside InstagramApi class :
private enum BaseURL: String { case displayApi = “https://api.instagram.com/" case graphApi = “https://graph.instagram.com/"}private enum Method: String { case authorize = “oauth/authorize” case access_token = “oauth/access_token”}
Step 3: Create a model file
Now, create a new swift file , name it InstagramResponse. Inside the file declare the below structs:
struct InstagramTestUser: Codable { var access_token: String var user_id: Int}struct InstagramUser: Codable { var id: String var username: String}struct Feed: Codable { var data: [MediaData] var paging: PagingData}struct MediaData: Codable { var id: String var caption: String?}struct PagingData: Codable { var cursors: CursorData var next: String}struct CursorData: Codable { var before: String var after: String}struct InstagramMedia: Codable { var id: String var media_type: MediaType var media_url: String var username: String var timestamp: String}enum MediaType: String,Codable { case IMAGE case VIDEO case CAROUSEL_ALBUM}
Step 4: Setting up the Viewcontroller in Storyboard
(If you want to use the SwiftUI instead of UIStoryboard you can follow this post :- https://medium.com/@tushargusain40/using-the-new-instagram-basic-display-api-using-swift-5-ios-bf06d93c4d8b?sk=b3f8d481076cc0ceb9e3c6161704b01e )
Add an imageView to your ViewController inside your Main.storyboard file and set it’s Content Mode to “Aspect fill”.
Constraint it as big as the superview, and above this Imageview add two buttons as shown in the preview below.
One button will be an “Instagram icon” and the other will be a “Fetch Image to background” text.
Now, go to your ViewController.swift file and add the following lines of code:-
var instagramApi = InstagramApi.sharedvar testUserData = InstagramTestUser(access_token: “”, user_id: 0)var instagramUser: InstagramUser?var signedIn = false@IBOutlet var backgroundImageView: UIImageView!@IBAction func authenticateOrSignIn(_ sender: UIButton) { }@IBAction func fetchImageToBackground(_ sender: UIButton) { }
Connect the backgroundImageView to the background image of the ViewController, authenticateOrSignIn with the “Instagram icon” Button and lastly, fetchImageToBackground to the “Fetch Image to Background” text Button.
On running the App you’ll get the following screen…
Now , you are all set to call the Instagram Api.
Getting your Access Token
Get Authorization
We need to authenticate the Test User, to do this we have to call the below url :
https://api.instagram.com/oauth/authorize?app_id={app-id}&redirect_uri={redirect-uri-urlencoded}&scope=user_profile,user_media&response_type=code
This will provide you with an authorization window, showing you the test user id that you added in the instagram app.
Go inside your InstagramApi class, create a function authorizeApp and paste the following code:
func authorizeApp(completion: @escaping (_ url: URL?) -> Void ) { let urlString = “\(BaseURL.displayApi.rawValue)\(Method.authorize.rawValue)?app_id=\(instagramAppID)&redirect_uri=\(redirectURIURLEncoded)&scope=user_profile,user_media&response_type=code” let request = URLRequest(url: URL(string: urlString)!) let session = URLSession.shared let task = session.dataTask(with: request, completionHandler: { data, response, error in if let response = response { print(response) completion(response.url) } }) task.resume()}
This function will call the above URL for authorization.
Now, go to the ViewController.swift class and add the following variable :
var testUserData = InstagramTestUser(access_token: “”, user_id: 0)
After this create a new Swift File, name it WebViewController. Then, add the following variables to the class:
import WebKitclass WebViewController: UIViewController, WKNavigationDelegate { var instagramApi: InstagramApi? var testUserData: InstagramTestUser? var mainVC: ViewController? @IBOutlet var webView: WKWebView! { didSet { webView.navigationDelegate = self } }}
Now, create a new ViewController in Main.storyboard file, add a Webkit View to it.Your Storyboard will look like this preview:
Select the class as WebViewController and write WebView inside Storyboard ID parameter.
After that connect the @IBOutlet var webView: WKWebView!!to the WebkitView inside the new ViewController.
Now, inside your WebViewController add the following three methods:
override func viewDidLoad() { super.viewDidLoad() //Authorize the user}func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { //Get user id and token decisionHandler(WKNavigationActionPolicy.allow)}func dismissViewController() { self.dismiss(animated: true) { self.mainVC?.testUserData = self.testUserData! }}
Then, inside your viewDidLoad method add the following lines of code:
override func viewDidLoad() { super.viewDidLoad() instagramApi?.authorizeApp { (url) in DispatchQueue.main.async { self.webView.load(URLRequest(url: url!)) } }}
Now, go inside your ViewController.swift file, add the following code to authenticateOrSignIn method:
@IBAction func authenticateOrSignIn(_ sender: UIButton) { if self.testUserData.user_id == 0 { presentWebViewController() } else { //get account user’s details}
After this add the following method to your ViewController class:
func presentWebViewController() { let storyBoard : UIStoryboard = UIStoryboard(name: “Main”, bundle:nil) let webVC = storyBoard.instantiateViewController(withIdentifier: “WebView”) as! WebViewController webVC.instagramApi = self.instagramApi webVC.mainVC = self self.present(webVC, animated:true)}
Now, run the app , clicking the instagram icon will present one of the following sheet as shown in the images below:
Enter your username & password(or click on the continue button if you got the second screen) to authorize the test user and grant your app access to your profile data. Upon success, the page will redirect you to the redirect URI you included in the previous step and append an Authorization Code. For example:
https://hotcocoasoftware.com/auth/?code=AQDp3TtBQQ...#_
Note:- #_ has been appended to the end of the redirect URI, but it is not part of the code itself.
Exchange the Code For a Token
Inside your InstagramApi class create a new function getTokenFromCallbackURL, and add the following code to it :
private func getTokenFromCallbackURL(request: URLRequest) -> String? { let requestURLString = (request.url?.absoluteString)! as String if requestURLString.starts(with: “\(redirectURI)?code=”) { print(“Response uri:”,requestURLString) if let range = requestURLString.range(of: “\(redirectURI)?code=”) { return String(requestURLString[range.upperBound…].dropLast(2)) } } return nil}
Add another private function getFormBody which will return a form-data made by the key value pairs. Add the following code to it :
private func getFormBody(_ parameters: [[String : String]], _ boundary: String) -> Data { var body = “” let error: NSError? = nil for param in parameters { let paramName = param[“name”]! body += “ — \(boundary)\r\n” body += “Content-Disposition:form-data; name=\”\(paramName)\”” if let filename = param[“fileName”] { let contentType = param[“content-type”]! var fileContent: String = “” do {
fileContent = try String(contentsOfFile: filename, encoding: String.Encoding.utf8)
} catch { print(error) } if (error != nil) { print(error!) } body += “; filename=\”\(filename)\”\r\n” body += “Content-Type: \(contentType)\r\n\r\n” body += fileContent } else if let paramValue = param[“value”] { body += “\r\n\r\n\(paramValue)” } } return body.data(using: .utf8)!}
To get the test user token and id we need to call the post method of the api whose curl representation is given below :
curl -X POST \https://api.instagram.com/oauth/access_token \-F app_id={app-id} \-F app_secret={app-secret} \-F grant_type=authorization_code \-F redirect_uri={redirect-uri} \-F code={code}
Upon success, the API will return a JSON encoded object containing an Instagram User Access Token and your Instagram test user’s ID:
{ “access_token”: “IGQVJ…”, “user_id”: 17841405793187218}
Now, inside your InstagramApi class create a new function getTestUserIDAndToken, and add the following code inside :
func getTestUserIDAndToken(request: URLRequest, completion: @escaping (InstagramTestUser) -> Void){ guard let authToken = getTokenFromCallbackURL(request: request) else { return } let headers = [ “content-type”: “multipart/form-data; boundary=\(boundary)” ] let parameters = [ [ “name”: “app_id”, “value”: instagramAppID ], [ “name”: “app_secret”, “value”: app_secret ], [ “name”: “grant_type”, “value”: “authorization_code” ], [ “name”: “redirect_uri”, “value”: redirectURI ], [ “name”: “code”, “value”: authToken ] ] var request = URLRequest(url: URL(string: BaseURL.displayApi.rawValue + Method.access_token.rawValue)!) let postData = getFormBody(parameters, boundary) request.httpMethod = “POST” request.allHTTPHeaderFields = headers request.httpBody = postData let session = URLSession.shared let dataTask = session.dataTask(with: request, completionHandler: {(data, response, error) in if (error != nil) { print(error!) } else { do {
let jsonData = try JSONDecoder().decode(InstagramTestUser.self, from: data!) print(jsonData) completion(jsonData) } catch let error as NSError { print(error) } } }) dataTask.resume()}
Now, go inside your WebViewController file ,inside the decidePolicyFor navigationAction method, add the following lines of code to call the getTestUserIDAndToken method :
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { let request = navigationAction.request self.instagramApi?.getTestUserIDAndToken(request: request) { [weak self] (instagramTestUser) in self?.testUserData = instagramTestUser DispatchQueue.main.async { self?.dismissViewController() } } decisionHandler(WKNavigationActionPolicy.allow)}
This will get the Test user’s ID and Token and save it in the binding variable testUserData.
Get the user’s feed
Query the User node
Now, you need to get the instagram user’s(who granted your app permission) id and username to get it’s feed.
We can get this data by the GET method of the InstagramApi given below :
“https://graph.instagram.com/{user-id}?fields=id,username&access_token={access-token}”
Upon success, the API will respond with your Instagram user’s ID and username:
{ “id”: “17841405793187218”, “username”: “username_xyz”}
Now, inside your InstagramApi class create a function getInstagramUser, and add the following code to it :
func getInstagramUser(testUserData: InstagramTestUser, completion: @escaping (InstagramUser) -> Void) { let urlString = “\(BaseURL.graphApi.rawValue)\(testUserData.user_id)?fields=id,username&access_token=\(testUserData.access_token)” let request = URLRequest(url: URL(string: urlString)!) let session = URLSession.shared let dataTask = session.dataTask(with: request, completionHandler: {(data, response, error) in if (error != nil) { print(error!) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse!) } do {
let jsonData = try JSONDecoder().decode(InstagramUser.self, from: data!) completion(jsonData) } catch let error as NSError { print(error) } }) dataTask.resume()}
Now go into your ViewController file and add a variable instagramUser :
var instagramUser: InstagramUser
After this add the following lines of code inside the authenticateOrSignIn method:
@IBAction func authenticateOrSignIn(_ sender: UIButton) { if self.testUserData.user_id == 0 { presentWebViewController() } else { self.instagramApi.getInstagramUser(testUserData: self.testUserData) { [weak self] (user) in self?.instagramUser = user self?.signedIn = true DispatchQueue.main.async { self?.presentAlert() }
} }
}
After this add the following method to your ViewController class :
func presentAlert() { let alert = UIAlertController(title: “Signed In:”, message: “with account: @\(self.instagramUser!.username)”, preferredStyle: UIAlertController.Style.alert) alert.addAction(UIAlertAction(title: “OK”, style: UIAlertAction.Style.default, handler: nil)) self.present(alert, animated: true)}
This will present an alert message on clicking the instagram icon Button once you have authorized the App. Inside the alert message , it will show the username of your instagram account as shown in the image below.
Get the User’s Media
Now you have the ID and the username of the Instagram user’s account, by knowing the user’s ID you can get the user’s details by calling this GET method of the Instagram Api:
“https://graph.instagram.com//me/media?fields={fields}&access_token={access-token}”
We will use “id,caption” as {fields} in this url parameter.
It will give the following response :
{ “data”: [ { “id”: “17895695668004550”, “caption”: “” }, { “id”: “17899305451014820”, “caption”: “” }, { “id”: “17896450804038745”, “caption”: “” }, { “id”: “17881042411086627”, “caption”: “” } ], “paging”: { “cursors”: { “after”: “MTAxN…”, “before”: “NDMyN…” }, “next”: “https://graph.faceb..." }}
Now, got to your InstagramApi class and create a new function getMediaData and add the following lines of code inside it :
private func getMediaData(testUserData: InstagramTestUser, completion: @escaping (Feed) -> Void) { let urlString = “\(BaseURL.graphApi.rawValue)me/media?fields=id,caption&access_token=\(testUserData.access_token)” let request = URLRequest(url: URL(string: urlString)!) let session = URLSession.shared let task = session.dataTask(with: request, completionHandler: { data, response, error in if let response = response { print(response) } do {
let jsonData = try JSONDecoder().decode(Feed.self, from: data!) print(jsonData) completion(jsonData) } catch let error as NSError { print(error) } }) task.resume()}
This will give you the whole array of your instagram account’s feed starting from the most recent one.
To fetch a single post, we will use the id of one of the post from the feed.
To get the data of a single post , we will use this GET method of the InstagramApi :
“https://graph.instagram.com/{media-id}?fields={fields}&access_token={access-token}”
For this we will replace the {fields} by “id,media_type,media_url,username,timestamp”
It will give the following response :
{ “id”: “17895695668004550”, “media_type”: “IMAGE”, “media_url”: “https://fb-s-b-a.akamaihd.net/...", “username”: “jayposiris”, “timestamp”: “2017–08–31T18:10:00+0000”}
Now, create a new function getMedia inside your InstagramApi class, and add the following code inside it :
func getMedia(testUserData: InstagramTestUser, completion: @escaping (InstagramMedia) -> Void) { getMediaData(testUserData: testUserData) { (mediaFeed) in let urlString = “\(BaseURL.graphApi.rawValue + mediaFeed.data[0].id)?fields=id,media_type,media_url,username,timestamp&access_token=\(testUserData.access_token)” let request = URLRequest(url: URL(string: urlString)!) let session = URLSession.shared let task = session.dataTask(with: request, completionHandler: { data, response, error in if let response = response { print(response) } do {
let jsonData = try JSONDecoder().decode(InstagramMedia.self, from: data!) print(jsonData) completion(jsonData) } catch let error as NSError { print(error) } }) task.resume() }}
You can use this feed data to show all of the posts’ data as a List in a TableView, and once the user clicks one of the post items in your list , show them the detailed post.It’s all up to you.
Here, we will be showing the first post that is the post at index 0 in the MediaFeed.data array(which is the latest post in your instagram account).
Now, inside the fetchImageToBackground method , call the getMedia method to get the latest post made by the Instagram account you are using. Add the following lines of code inside it.
@IBAction func fetchImageToBackground(_ sender: UIButton) { if self.instagramUser != nil { self.instagramApi.getMedia(testUserData: self.testUserData) { (media) in if media.media_type != MediaType.VIDEO { let media_url = media.media_url self.instagramApi.fetchImage(urlString: media_url, completion: { (fetchedImage) in if let imageData = fetchedImage { DispatchQueue.main.async { self.backgroundImageView.image = UIImage(data: imageData) } } else { print(“Didn’t fetched the data”) } }) print(media_url) } else { print(“Fetched media is a video”) } } } else { print(“Not signed in”) }}
Now, create a function fetchImage inside your InstagramApi class, this function will fetch an image from the given url. Inside this functions body add the following lines of code :
func fetchImage(urlString: String, completion: @escaping (Data?) -> Void) { let request = URLRequest(url: URL(string: urlString)!) let session = URLSession.shared let task = session.dataTask(with: request, completionHandler: { data, response, error in if let response = response { print(response) } completion(data) }) task.resume()}
Now, on clicking the Fetch Image to background you will see you latest posted Image on the background of your app, as shown in the preview below :
Congratulations!!! , you fetched your instagram account’s feed from the Instagram Api provided by Facebook.
And with that my friend, you are done. Great job!
You can find the whole code for this app here at : https://github.com/tushar40/InstaApp_storyboard
I hope you enjoyed this tutorial. Feel free to post your questions and comments on the forums, I can’t wait for what you guys come up with for your next great app! ;)
This is a post by Tushar Gusain, an Android/iOS developer.