How to Make HTTP Requests in Swift 3

August 22, 2017
Written by
Sam Agnew
Twilion

HTTP Requests In Swift 3

Making HTTP requests is core functionality for modern languages and one of the first things many developers learn when acclimating to new environments. When it comes to Swift there are a fair amount of solutions to this problem both built into the language and by the community. Let’s take a look at some of the most popular ones.

We’ll be using NASA’s Astronomy Picture of the Day API as the JSON API that we are interacting with in all of these examples because space is the coolest thing ever.

giphy.gif

Before moving on, make sure you have up to date versions of Swift 3 on your machine. If you use OSX, you can install Xcode from that link and have Swift available on the command line. If you use Linux, you can download it using the previous link as well. For Windows users, this might be helpful.

Swift in the Terminal

We are going to use Swift on the command line in all of the following examples. This doesn’t mean you can’t copy and paste any of this to Xcode, but Swift has an array of useful command line utilities that make testing the code in this tutorial easy.

Follow along by opening your terminal and navigating to the directory where you want this code to live. My directory is named SwiftHTTP which you will see in the examples in the rest of this post.

Enter the following to generate an executable command line project:

swift package init --type executable

This will also generate a Package.swift file for you. With this, we can add dependencies to use Swift Package Manager for installing third party libraries.

HTTP Requests with URLRequest

First up, we are going to use a built-in API called URLRequest. This method is pretty straightforward, and the code is much better in Swift 3 than in earlier versions of the language.

If you’re following along using the command line, open up main.swift in the Sources directory that was generated from the previous command, and enter the following code:

import Foundation

// Set the URL the request is being made to.
let request = URLRequest(url: NSURL(string: "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY")! as URL)
do {
    // Perform the request
    var response: AutoreleasingUnsafeMutablePointer<URLResponse?>? = nil
    let data = try NSURLConnection.sendSynchronousRequest(request, returning: response)

    // Convert the data to JSON
    let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]

    if let json = jsonSerialized, let url = json["url"], let explanation = json["explanation"] {
        print(url)
        print(explanation)
    }
}

That’s all you need to do to make an HTTP request. Head back to your terminal and run the following command, keeping in mind that you might have to modify this to fit the name of your Swift project:

swift build && .build/debug/SwiftHTTP

You should see the URL and an explanation of the Astronomy Picture of the Day printed out on the screen.

giphy.gif

HTTP Requests with URLSession

URLSession is another popular way to send HTTP requests that’s built into the language. URLSession also doesn’t execute requests off of the main thread, which is pretty nifty.

Modify main.swift to include the following code:

import Foundation

let url = URL(string: "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY")

let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in

    if let data = data {
        do {
            // Convert the data to JSON
            let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]

            if let json = jsonSerialized, let url = json["url"], let explanation = json["explanation"] {
                print(url)
                print(explanation)
            }
        }  catch let error as NSError {
            print(error.localizedDescription)
        }
    } else if let error = error {
        print(error.localizedDescription)
    }
}

task.resume()

// Infinitely run the main loop to wait for our request.
// Only necessary if you are testing in the command line.
RunLoop.main.run()

The example we used before with URLRequest was synchronous, but this one is asynchronous. For this reason, we are calling RunLoop.main.run() at the end to make sure the script doesn’t finish executing before the request is responded to. Feel free to take that last line out if you are using this code in a different context.

Just like before, run this code:

swift build && .build/debug/SwiftHTTP

Once you get a response, kill the script with ctrl-c.

HTTP Requests with Alamofire

The previous methods have been built into the language. But there are also third-party networking libraries in Swift. Alamofire is an excellent (and also the most popular) in the Swift community.

Alamofire is a user-friendly and versatile library with a lot of options. It has chainable request and response methods, and takes care of boilerplate functionality such as validating HTTP responses.

Unlike the other examples, we need to modify Package.swift for this to work. We’ll also be using another library called SwiftyJSON, which makes parsing JSON more user-friendly and works very well with Alamofire.

Replace the code inside Package.swift with the following to add Alamofire and SwiftyJSON as dependencies:

import PackageDescription

let package = Package(
   name: "SwiftHTTP",
   dependencies: [
       .Package(url: "https://github.com/Alamofire/Alamofire.git", majorVersion: 4),
       .Package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", majorVersion: 3, minor: 1)
   ]
)

Now head back to main.swift to change the code to use Alamofire:

import Foundation
import Alamofire
import SwiftyJSON

Alamofire.request("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY").responseJSON { response in
    if let result = response.result.value {
        let json = JSON(result)
        print(json["url"])
        print(json["explanation"])
    }
}

RunLoop.main.run()

Just like in our previous option, the request is asynchronous so we are calling RunLoop.main.run(). Feel free to remove that line if you are adding this to an Xcode project.

Final Thoughts

Now we’ve covered the basics, but there are a few other open source libraries that are worth looking into. Just is a very simple HTTP library inspired by the Python requests module, and SwiftHTTP is another lightweight solution.

There is also another rad library called Siesta, which makes working with REST APIs a breeze.

This doesn’t cover all of the solutions, but now you see how the basic functionality works for a few of the most popular ways to make HTTP requests in Swift.

Other languages have a similar variety of methods to tackle this problem. Check out these other tutorials for Node.js, Python and Ruby.

What are your favorite ways to send HTTP requests? Feel free to reach out and let me know or ask any questions: