Alamofire Tutorial for iOS: Advanced Usage

In this tutorial, you’ll learn about the advanced usage of Alamofire. Topics include handling OAuth, network logging, reachability, caching and more. By Vidhur Voora.

5 (23) · 3 Reviews

Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

GitHub Authorization

To fetch your private repositories, you need to log in to GitHub through your app. There are two ways an app can get authorization to access GitHub API:

  • Basic Authentication: This involves passing the username and password as part of the request.
  • OAuth 2.0 token: OAuth 2.0 is an authorization framework that gives an app access to user accounts for an HTTP service.

In this tutorial, you’ll learn to work with an OAuth 2.0 token.

OAuth Overview

There are several steps to authorize an app to access user repositories via OAuth 2.0:

  1. The app makes a network request for authorization.
  2. Then, the user logs in to GitHub for the authorization to succeed.
  3. Next, GitHub redirects back to the app with a temporary code.
  4. The app requests an access token using that temporary code.
  5. On receiving the access token, the app makes an API request to fetch the user’s private repositories. The request’s authorization header will contain the access token.

GitHub OAuth Overview

Next, you’ll create a GitHub OAuth app.

Creating GitHub OAuth App

Log in to GitHub and follow these steps to create an OAuth app with the settings shown below:

  1. Enter GitOnFire as the Application name.
  2. Enter https://www.raywenderlich.com/ as Homepage URL.
  3. Skip the Application description.
  4. Enter gitonfire:// as the Authorization callback URL.

Register GitHub OAuth applicatoin

Logging Into GitHub

Once you’ve registered an app, copy the Client ID and Client Secret values. Then in your Xcode project, open GitHubConstants.swift and update clientID and clientSecret with the corresponding values.

Next, open GitAPIManager.swift and add the following method just before the closing brace:

func fetchAccessToken(
  accessCode: String,
  completion: @escaping (Bool) -> Void
) {
  // 1
  let headers: HTTPHeaders = [
    "Accept": "application/json"
  ]
  // 2
  let parameters = [
    "client_id": GitHubConstants.clientID,
    "client_secret": GitHubConstants.clientSecret,
    "code": accessCode
  ]
  // 3
  sessionManager.request(
    "https://github.com/login/oauth/access_token",
    method: .post,
    parameters: parameters,
    headers: headers)
    .responseDecodable(of: GitHubAccessToken.self) { response in
      guard let cred = response.value else {
        return completion(false)
      }
      TokenManager.shared.saveAccessToken(gitToken: cred)
      completion(true)
    }
}

Here’s a step-by-step breakdown:

To learn more about using keychain and storing secure information, read this KeyChain Services API Tutorial for Passwords in Swift.

  1. You define the headers for the request. Accept with application/json tells the server the app wants the response in JSON format.
  2. Then you define the query parameters client_id, client_secret and code. These parameters are sent as part of the request.
  3. You make a network request to fetch the access token. The response is decoded to GitHubAccessToken. The TokenManager utility class helps store the token in the keychain.

    To learn more about using keychain and storing secure information, read this KeyChain Services API Tutorial for Passwords in Swift.

Open LoginViewController.swift. In getGitHubIdentity(), replace //TODO: Call to fetch access token will be added here with the following:

GitAPIManager.shared.fetchAccessToken(accessCode: value) { [self] isSuccess in
  if !isSuccess {
    print("Error fetching access token")
  }
  navigationController?.popViewController(animated: true)
}

Here, you make a call to fetch the access token using the temporary code. Once the response succeeds, the controller shows the list of repositories.

Now open RepositoriesViewController.swift. In viewDidLoad(), remove the following line :

loginButton.isHidden = true

This displays the login button. Build and run.

Oauth Login via Alamofire

Tap Login to log in. The browser will then redirect you back to the app, and the login button will change to logout. You’ll see the access token and scope in the console.

Access Token in console

Great job! Now it’s time to fetch your repositories.

Fetching User Repositories

Open GitAPIManager.swift. In GitAPIManager, add the following method:

func fetchUserRepositories(completion: @escaping ([Repository]) -> Void) {
  //1
  let url = "https://api.github.com/user/repos"
  //2
  let parameters = ["per_page": 100]
  //3
  sessionManager.request(url, parameters: parameters)
    .responseDecodable(of: [Repository].self) { response in
      guard let items = response.value else {
        return completion([])
      }
      completion(items)
    }
}

Here’s what you added:

  1. You define the URL to fetch your repositories.
  2. The per_page query parameter determines the maximum number of repositories returned per response. The maximum results you can get per page is 100.
  3. Next, you make a request to fetch your repositories. You then decode the response into an array of Repository and pass it in the completion block.

Next, open RepositoriesViewController.swift and find fetchAndDisplayUserRepositories(). Replace //TODO: Add more here.. with the following:

//1
loadingIndicator.startAnimating()
//2
GitAPIManager.shared.fetchUserRepositories { [self] repositories in
  //3
  self.repositories = repositories
  loadingIndicator.stopAnimating()
  tableView.reloadData()
}

Here’s a code breakdown:

By default, Alamofire calls the response handlers on the main queue. So, you don’t have to add code to switch to the main thread to update UI.

  1. You display a loading indicator before making a network request.
  2. Then, you make a network request to fetch your repositories.
  3. Once your repositories are fetched, you set repositories with the response and dismiss the loading indicator. You then reload the table view to show the repositories.

    By default, Alamofire calls the response handlers on the main queue. So, you don’t have to add code to switch to the main thread to update UI.

Build and run.

Empty List

The list is empty! Check the Xcode console, and you’ll see a 401 unauthorized request.

Alamofire Unauthorized request

You have to pass in the access token in a header for authorization. You could add anAuthentication header inside fetchUserRepositories(completion:) in GitAPIManager. However, the process of adding headers individually for each request may become repetitive.

To help avoid this, Alamofire provides RequestInterceptor, a protocol that enables powerful per-session and per-request capabilities.

Request Overview

Before diving into RequestInterceptor, you should understand the different types of Requests.

Alamofire’s Request is a superclass of all requests. There are several types:

  • DataRequest: Encapsulates URLSessionDataTask by downloading the server response into data stored in memory.
  • DataStreamRequest: Encapsulates URLSessionDataTask and streams data from an HTTP connection over time.
  • UploadRequest: Encapsulates URLSessionUploadTask and uploads data to a remote server.
  • DownloadRequest: Encapsulates URLSessionDownloadTask by downloading response data to the disk.

Alamofire Request Types

Each request starts in an initialized state. It can either be suspended, resumed or canceled during its lifetime. The request ends in a finished state.

Currently, you’re using a DataRequest to fetch your repositories. Now you’re going to intercept your requests using RequestInterceptor.

RequestInterceptor Overview

Alamofire’s RequestInterceptor consists of two protocols: RequestAdapter and RequestRetrier.

RequestAdapter lets you inspect and mutate each request before sending it. This is ideal when every request includes an Authorization header.

RequestRetrier retries a request that encountered an error.