10.6. Fetching Data with AlamoFire: GET

http://apis.sakibnm.work:8888/contacts/text/getall

It's time to fetch the contacts' names and display them in our table view. We will call the API with getall endpoint when the app starts, and display the response on the table view (10.3. Testing our Simple Custom API with Postman).

Using Alamofire for text responses

If you noticed, in our API, we are getting back text responses from the server. We will use Alamofire to process the responses. Before we do, let's define an array of Strings in our ViewController for populating the table view. That array will hold the names of the contacts returned by the API endpoint getall.

//
//  ViewController.swift
//  App10
//
//  Created by Sakib Miazi on 5/25/23.
//

import UIKit
import Alamofire

class ViewController: UIViewController {
    
    let mainScreen = MainScreenView()
    
    //MARK: list to display the contact names in the TableView...
    var contactNames = [String]()
    
    //codes omitted...
}

First, we need the API base URL to be set up. You can directly use the URL string in the call; however, it is always a better practice if you save these API details in a separate file as a static String, so that you can reuse that from any screen if you need to.

Let's create a file named APIConfigs.swift under App10 folder. It is a Swift class file, not a CocoaTouch Class.

In APIConfig.swift, let's add the static constant for the base URL:

You can access the base URL by writing APIConfigs.baseURL from anywhere in the project.

The 'getall' endpoint with Alamofire

Now, let's write a function to call the getall API endpoint and load the names in contactNames array.

First of all, you need to import the Alamofire library.

Let's look at the function getAllContacs() method definition:

  • First, we build the URL with the baseURL and the getall endpoint using URL() initializer. URL() returns a URL wrapped with optional (in case it cannot create a valid URL, it returns an Optional(nil)). We have to unwrap it. So we unwrap it and put it in the constant url.

  • Then we use url to make a request with Alamofire. We use AF to use Alamofire functions. So, here we are creating an Alamofire request with the url we built.

  • If you noticed, we set the method of the request to .get. Remember, getall endpoint of the API server expects a GET request.

  • Then we call the responseString() method for the request. We are handling text responses, right? So, we need to catch String-type data from the response we get from the server.

  • Then we write a closure completionHandler to deal with the data after we receive the response. Please note any communication over the Internet is Asynchronous. That means we are dealing with data that are hosted probably hundreds if not thousands of miles away. So, it will take time to receive the response from the server after you send the request. It might feel like it's real-time, but logically, it's not. So, when we build apps that communicate over the Internet, we must be very careful dealing with it. We should not expect that we will receive the response right away.

  • In the closure, we print response.result to see what kind of data we received as the response. If you run the app now, It prints something like this: success("Alice Smith\nBob Smith\nDavid B\nAlex C\nMark W\n")

    • success() in the response means the request was successfully transmitted, and there was no network error.

    • See, we have in between two consecutive names. The character means a new line. So, we have to fetch the whole String and then use it.

  • Also, the status code the response has is very important. We need to check if it is a 200-level or a 400-level code.

    • 200-level codes mean the request was valid, and we received a desirable response.

    • 400-level codes mean the request was incorrect, so we must handle the response appropriately to manage the UI elements properly.

So, let's write the following code in the completionHandler closure taking care of the status codes and network errors:

In the above code:

  • First, we retrieve the status code from the response (at line 6). It is an optional value. So, we need to unwrap it when we use it.

  • Then we check for network errors from response.result. (At line 8).

    • If there is no network error, we now check if the status code is a 200-level- or 400-level.

    • If the code is a 200-level code:

      • Then we separate each line by splitting the data using the delimiter . (At line 17).

      • Then we set the Strings from data to contactNames array.

      • And then, we print the array.

    • If the code is 400- or 500-level, we print the debug log for now. You might want to handle these conditions depending on the app's needs.

  • We might need to check our internet connection if there is a network failure. (at line 36).

Now, if we run the app, it will run, but you won't see any items printed. If you check the outputs, you might see something like the following:

By default, iOS does not allow HTTP connections without encryption. We should always use the connections through HTTPS.

However, since my API is a dumb API, and I am using the API for demonstration purposes, I didn't go through the HTTPS configuration process. So, we need to enable unencrypted HTTP connections in our app.

If you face this, you can solve this by doing the following:

Enabling unencrypted HTTP in our app

  • We need to open Info.plist file from the File Navigator of the project.

  • Right-click (control + click) on the empty space of Info.plist.

  • Select Add Row.

  • Search and Select "App Transport Security Settings."

    • Inside "App Transport Security Settings," add an attribute by clicking plus icon(+).

    • Set "Allow Arbitrary Loads" attribute's value to YES.

It should now allow unencrypted HTTP.

If we run the app now, it should print the following:

["Alice Smith", "Bob Smith", "David B", "Alex C", "Mark W", ""].

Interestingly, there is an empty String at the end. This happens because the server adds a character at the end of the last user's name. So we need to remove it from the contactNames.

Let's add self.contactNames.removeLast() after line 18.

Now, we have the perfect contactNames array to be displayed in the table view.

Displaying data on the table view

Now, let's adopt the protocols for the table view:

Then, set the delegate and data source in viewDidLoad() method.

In the above code, at line 11, we remove the separator line of the table view. If you want to remove the line, you get to do this after the table view is populated. If you add this instruction when setting up the table view, it will not work. So, we write this code in the controller.

If you run the app now, the table view remains empty. As I discussed before, the internet calls are asynchronous. So, we need to wait until the response is received. Once we receive the response, we should reload the data for the table view. Hence, we add the following line into getAllContacts() method after we remove the last element from contactNames: self.mainScreen.tableViewContacts.reloadData().

The final getAllContacts() method looks as follows:

Let's run the app again. It should look like this:

Last updated

Was this helpful?