Alamofire Tutorial: Getting Started

Take your first steps into Alamofire, the de facto networking library on iOS powering thousands of apps, by using the Imagga APIs to upload and analyze user photos. By Ron Kliffer.

Leave a rating/review
Download materials
Save for later
Share
Update note: This tutorial has been updated to Xcode 9.3, iOS 11.3, Swift 4.1 and Alamofire 4.7.0 by Ron Kliffer. The original tutorial was written by Aaron Douglas.

Alamofire is a Swift-based HTTP networking library for iOS and macOS. It provides an elegant interface on top of Apple’s Foundation networking stack that simplifies a number of common networking tasks.

Alamofire provides chainable request/response methods, JSON parameter and response serialization, authentication, and many other features.

In this Alamofire tutorial, you’ll use Alamofire to perform basic networking tasks like uploading files and requesting data from a third-party RESTful API.

Alamofire’s elegance comes from the fact it was written from the ground up in Swift and does not inherit anything from its Objective-C counterpart, AFNetworking.

You should have a conceptual understanding of HTTP networking and some exposure to Apple’s networking classes such as URLSession.

While Alamofire does obscure some implementation details, it’s good to have some background knowledge if you ever need to troubleshoot your network requests.

Getting Started

Use the Download Materials button at the top or bottom of this tutorial to download the starter project.

Note: Alamofire is normally integrated using CocoaPods. It has already been installed for you in the downloaded projects.

The app for this Alamofire tutorial is named PhotoTagger. When complete, it will let you select an image from your library (or camera if you’re running on an actual device) and upload the image to a third-party service called Imagga. This service will perform some image recognition tasks to come up with a list of tags and primary colors for the image:

alamofire tutorial

This project uses CocoaPods, so open it using the PhotoTagger.xcworkspace file.

Note:To learn more about CocoaPods, check out this tutorial by Joshua Greene, published right here on the site.

Note:To learn more about CocoaPods, check out this tutorial by Joshua Greene, published right here on the site.

Build and run the project. You’ll see the following:

alamofire tutorial

Click Select Photo and choose a photo. The background image will be replaced with the image you chose.

Open Main.storyboard and you’ll see the additional screens for displaying tags and colors have been added for you. All that remains is to upload the image and fetch the tags and colors.

The Imagga API

Imagga is an image recognition Platform-as-a-Service that provides image tagging APIs for developers and businesses to build scalable, image-intensive cloud apps. You can play around with a demo of their auto-tagging service here.

You’ll need to create a free developer account with Imagga for this Alamofire tutorial. Imagga requires an authorization header in each HTTP request so only people with an account can use their services. Go to https://imagga.com/auth/signup/hacker and fill out the form. After you create your account, check out the dashboard:

Listed down in the Authorization section is a secret token you’ll use later. You’ll need to include this information with every HTTP request as a header.

Note: Make sure you copy the whole secret token, be sure to scroll over to the right and verify you copied everything.

Note: Make sure you copy the whole secret token, be sure to scroll over to the right and verify you copied everything.

You’ll be using Imagga’s content endpoint to upload the photos, tagging endpoint for the image recognition and colors endpoint for color identification. You can read all about the Imagga API at http://docs.imagga.com.

REST, HTTP, JSON — What’s that?

If you’re coming to this tutorial with very little experience in using third-party services over the Internet, you might be wondering what all those acronyms mean! :]

HTTP is the application protocol, or set of rules, web sites use to transfer data from the web server to your screen. You’ve seen HTTP (or HTTPS) listed in the front of every URL you type into a web browser. You might have heard of other application protocols, such as FTP, Telnet, and SSH. HTTP defines several request methods, or verbs, the client (your web browser or app) use to indicate the desired action:

  • GET: Retrieves data, such as a web page, but doesn’t alter any data on the server.
  • HEAD: Identical to GET but only sends back the headers and none of the actual data.
  • POST: Sends data to the server, commonly used when filling a form and clicking submit.
  • PUT: Sends data to the specific location provided.
  • DELETE: Deletes data from the specific location provided.

REST, or REpresentational State Transfer, is a set of rules for designing consistent, easy-to-use and maintainable web APIs. REST has several architecture rules that enforce things such as not persisting states across requests, making requests cacheable, and providing uniform interfaces. This makes it easy for app developers like you to integrate the API into your app, without needing to track the state of data across requests.

JSON stands for JavaScript Object Notation. It provides a straightforward, human-readable and portable mechanism for transporting data between two systems. JSON has a limited number of data types: string, boolean, array, object/dictionary, null and number. There’s no distinction between integers and decimals.

There are a few native choices for converting your objects in memory to JSON and vice-versa: the good old JSONSerialization class and the newly-added JSONEncoder and JSONDecoder classes. In addition, there are numerous third party libraries that help with handling JSON. You’ll use one of them, SwiftyJSON in this tutorial.

The combination of HTTP, REST and JSON make up a good portion of the web services available to you as a developer. Trying to understand how every little piece works can be overwhelming. Libraries like Alamofire can help reduce the complexity of working with these services, and get you up and running faster than you could without their help.

What is Alamofire Good For?

Why do you need Alamofire at all? Apple already provides URLSession and other classes for downloading content via HTTP, so why complicate things with another third party library?

The short answer is Alamofire is based on URLSession, but it frees you from writing boilerplate code which makes writing networking code much easier. You can access data on the Internet with very little effort, and your code will be much cleaner and easier to read.

There are several major functions available with Alamofire:

  • Alamofire.upload: Upload files with multipart, stream, file or data methods.
  • Alamofire.download: Download files or resume a download already in progress.
  • Alamofire.request: Every other HTTP request not associated with file transfers.

These Alamofire methods are global within Alamofire so you don’t have to instantiate a class to use them. There are underlying pieces to Alamofire that are classes and structs, like SessionManager, DataRequest, and DataResponse; however, you don’t need to fully understand the entire structure of Alamofire to start using it.

Here’s an example of the same networking operation with both Apple’s URLSession and Alamofire’s request function:

// With URLSession
public func fetchAllRooms(completion: @escaping ([RemoteRoom]?) -> Void) {
  guard let url = URL(string: "http://localhost:5984/rooms/_all_docs?include_docs=true") else {
    completion(nil)
    return
  }

  var urlRequest = URLRequest(url: url,
                              cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
                              timeoutInterval: 10.0 * 1000)
  urlRequest.httpMethod = "GET"
  urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")

  let task = urlSession.dataTask(with: urlRequest)
  { (data, response, error) -> Void in
    guard error == nil else {
      print("Error while fetching remote rooms: \(String(describing: error)")
      completion(nil)
      return
    }

    guard let data = data,
      let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
        print("Nil data received from fetchAllRooms service")
        completion(nil)
        return
    }

    guard let rows = json?["rows"] as? [[String: Any]] else {
      print("Malformed data received from fetchAllRooms service")
      completion(nil)
      return
    }

    let rooms = rows.flatMap { roomDict in return RemoteRoom(jsonData: roomDict) }
    completion(rooms)
  }

  task.resume()
}

Versus:

// With Alamofire
func fetchAllRooms(completion: @escaping ([RemoteRoom]?) -> Void) {
  guard let url = URL(string: "http://localhost:5984/rooms/_all_docs?include_docs=true") else {
    completion(nil)
    return
  }
  Alamofire.request(url,
                    method: .get,
                    parameters: ["include_docs": "true"])
  .validate()
  .responseJSON { response in
    guard response.result.isSuccess else {
      print("Error while fetching remote rooms: \(String(describing: response.result.error)")
      completion(nil)
      return
    }

    guard let value = response.result.value as? [String: Any],
      let rows = value["rows"] as? [[String: Any]] else {
        print("Malformed data received from fetchAllRooms service")
        completion(nil)
        return
    }

    let rooms = rows.flatMap { roomDict in return RemoteRoom(jsonData: roomDict) }
    completion(rooms)
  }
}

You can see the required setup for Alamofire is shorter and it’s much clearer what the function does. You deserialize the response with responseJSON(options:completionHandler:) and calling validate() to verify the response status code is in the default acceptable range between 200 and 299 simplifies error condition handling.

Now the theory is out of the way, it’s time to start using Alamofire.