HTTP JSON Requests with Swift and Alamofire

Categories:

Editor’s note: See our latest post on using Carthage for adding Alamofire to your project. You don’t need to suffer through git submodules (the method described below) any longer.

It didn’t take long after the introduction of Swift to begin seeing Stackoverflow questions asking about using AFNetworking, the popular Objective-C framework for making HTTP requests on iOS. Of course it can be done, as Swift and Objective-C can coexist together in the same project, but there’s the Objective-C way of doing things, and then there is the Swift way. Enter Alamofire, brought to you by the same author as AFNetworking.

As you can guess, we’re interested in using this new framework with our Swift projects. Let’s get to it shall we. This tutorial will walk you through creating a new Xcode project using Swift to make use of the MyMemory language translator to translate simple phrases from English to Spanish. Of course we could have built an application that allowed the user to choose the source and destination languages, but we wanted to leave it as an exercise to the reader.

Before you get started, I should point out that I’m using Xcode 6.1 (6A1052d). If you are using a different version, well, as they say, YMMV. While I suggest you go through this tutorial step-by-step, you can fast forward and download the working project on Bitbucket (see the end of this post for instructions to ensure Alamofire is updated in your checkout).

Start Xcode and select File – New Project and create a Single View iOS application. For the Product Name we chose translator, and of course make sure your language is Swift.

Before getting to Alamofire, let’s create a UI. Click on Main.storyboard to bring it up.

Drag four labels and a text input field to the storyboard, arranged as follows:

alamofire_constraints

In this example we have also added constraints to the layout. I’m by no means an expert on using Xcode constraints, but if I did it correctly the UI should look appropriate on the iPhone 5, 6, or 6 Plus. The layout should also rotate correctly.

Wire up the Text Field to the view controller as an IBOutlet. In this example I’ve named it textFieldToTranslate. Also wire up the label where we’ll display our translated text. I’ve named it translatedTextLabel.

alamofire_addtextfieldtotranslate

Your IBOutlets in ViewController.swift should look like:

[objc]
@IBOutlet weak var textFieldToTranslate: UITextField!
@IBOutlet weak var translatedTextLabel: UILabel!
[/objc]

Now, let’s add the appropriate delegate methods to the view controller so we can interact with the text field. This includes:

  • Adding UITextFieldDelegate to the ViewController class declaration
  • Setting the delegate property of the UITextField to the view controller
  • Adding the textFieldShouldReturn function to the ViewController class

I typically set the UITextField delegate property in the view controller viewDidAppear method, so let’s add that:

[objc]
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)

self.textFieldToTranslate.delegate = self
}

func textFieldShouldReturn(textField: UITextField) -> Bool {

textField.resignFirstResponder()

return true
}
[/objc]

We can compile and run our code as is, but of course it does next to nothing. Now, let’s wire up Alamofire to translate the text that is in the text field.

Using Alamofire

Alamorefire’s set up is a bit different than with Objective-C frameworks. The Alamofire Github repository currently states, Due to the current lack of proper infrastructure for Swift dependency management, using Alamofire in your project requires the following steps, followed by 7 steps to follow. We’re going to follow those here, with some additional detail provided.

Open a terminal (again, I like iTerm 2), and cd over to your Xcode project directory. In our case we cd ~/projects/blogging/translator, and use the git submodule feature to check the Alamofire code as a git submodule:

alamofire_addsubmodule

Now, with the Mac Finder, locate your project directory, navigate into the Alamofire folder, and drag-and-drop the Alamofire.xcodeproj icon from the Finder window into the Xcode project.

alamofire_addingxcodeproj

You should now see something like this in your Xcode project:

alamofire_addxcodeproj

Now, in Xcode, navigate to the target configuration window of Alamofire by clicking on the blue Alamofire project icon, and selecting the application target under the Targets heading in the sidebar. Ensure here that the Deployment Target of Alamofire is the same as the Deployment Target of the translator application. In our case, we are using a deployment target of 8.0.

alamoFireTarget

Now, click on the translator project icon (the blueprint icon), select the translator target and in the tab bar at the top of that window open the Build Phases panel. Expand the Target Dependencies group, and add Alamofire:

alamofire_targetdependency_alamofire

Finally, click on the + button at the top left of the panel (right under the label that says General and select New Copy Files Phase.

alamofire_copyfilesphase

Rename this new phase to Copy Frameworks, set the Destination to Frameworks, and add Alamofire.framework.

alamofire_addalamofireframework

And that’s all there is to it! Okay, so it’s a pain in the ass doing all that, but I find it worth the trouble. For a minute or two of drag-and-drop-and-configure we have an excellent API to begin making HTTP requests with.

Now that we have Alamofire added, let’s use it in our textFieldShouldReturn function. Remember, textFieldShouldReturn is going to get called when the user presses the action key on the iOS keyboard associated with our text field. First, add the statement import Alamofire at the top of your ViewController.swift file, like such:

[objc]
import Alamofire
[/objc]

Then, in textFieldShouldReturn we’ll do the following:

[objc]
let textToTranslate = self.textFieldToTranslate.text

let parameters = ["q":textToTranslate,
"langpair":"en|es"]

Alamofire.request(.GET, "http://api.mymemory.translated.net/get", parameters:parameters)
.responseJSON { (_, _, JSON, _) -> Void in

let translatedText: String? = JSON?.valueForKeyPath("responseData.translatedText") as String?

[/objc]

We’re following the API at MyMemory for translating text from English to Spanish. Notice the simplicity of both the HTTP request with Alamofire as well as handling the response. .GET is an enumeration for the HTTP method to use for the request, followed by our URL, and then a basic dictionary of URL parameters.

The MyMemory API call returns a JSON string, so we can utilize the Alamofire responseJSON function to give us a JSON dictionary (it handles taking the JSON string returned in the body and converting it for us). Although it looks careless the method in which we are getting the translatedText is good form. Since we declare translatedText as String? we are saying “This could be a String or nil.” Moreover, by using JSON?.valueForKeyPath() we are saying, “JSON could respond to valueForKeyPath or it could be nil“. If JSON is nil then it follows translatedText will be nil as well. If JSON is not nil and we find a value at the given key path responseData.translatedText, then we have our translation available (which we’ll display in the label).

All of this code makes heavy use of chained optionals in Swift. For a refresher in Swift optionals in general, visit our post on the topic.

Once we have the translated text we update our view controller label:

[objc]
if let translated = translatedText {
self.translatedTextLabel.text = translated
} else {
self.translatedTextLabel.text = "No translation available."
}
[/objc]

Alamofire has a lot of features, and of course we’ve only scratched the surface. Take a look through the extensive documentation on Github; it’s all there, support for POST and the remaining cast of characters, various authentication methods (eg., basic auth), uploading data, etc.

Let’s run our new application and translate Good night, friends! into Spanish.

translator_run

Nice, it worked! Of course, my Spanish-speaking amigos will point out that the opening signo de exclamación is missing, but that can be corrected.

That’s it for today, I hope you enjoyed the tutorial. Again, if you’d like a working example visit the Bitbucket repository. After checking out the repository, make sure and run the following in your alamofire-translator directory:

Exercises for the Reader

You will no doubt notice that the application is only capable of translating from English to Spanish. MyMemory allows for any-to-any translation, why not add a popup menu to allow for choosing which language to translate from and to? And while the HTTP request is pretty quick there’s room perhaps for a progress indicator somewhere on the screen, as either a HUD or basic activity spinner.

3 thoughts on “HTTP JSON Requests with Swift and Alamofire”

  1. Great article – it was most helpful.

    I do have a related question that I would think would be quite common, but I cannot seem to find an answer to it anywhere. When I follow your instructions to add Alamofire as a submodule, and then change the Deployment Target in the Alamofire.xcodeproj file to match my project settings, the project file is obviously now dirty. What is the proper way to handle this from a SCM perspective? It seems creating a fork just for this is silly. How do you handle this?

    Apologies in advance if this is a noob question ;(

    I do see someone else asking the exact same question here http://stackoverflow.com/q/26695627, but alas no one has answered it.

    Any assistance you can give would be greatly appreciated…

Leave a Reply

Your email address will not be published. Required fields are marked *