How Do Alamofire Routers Work?
April 06, 2016

Sometimes we read tutorials or books and the code seems like magic. It works but it’s really not clear why. Especially when it’s full of weird Swift stuff like enums and computed properties and pattern matching. It’s enough to make you want to curl up in bed and give up on programming altogether.

Pug curled up in blanket in bed
How “magic” code makes me feel (image by Matthew Wiebe)

A reader pointed out recently that my Alamofire router code is guilty of showing fancy code with funky Swift features. And the blog post doesn’t make it clear what’s happening. So today I’ll make things right and we’ll figure out exactly how something like Alamofire.request(Router.Get(1)).responseJSON… actually works.

Here’s the question I was asked:

In the Router, you use case Get(Int) but I never see var URLRequest: NSMutableURLRequest actually get called. All I see is Alamofire.request(Router.Get(1)).responseJSON…. How does the computed property get called?

In case you don’t have a photographic memory, here’s how we declared the router:

enum PostRouter: URLRequestConvertible {
  static let baseURLString = "http://jsonplaceholder.typicode.com/"
  
  case Get(Int)
  case Create([String: AnyObject])
  case Delete(Int)
  
  var URLRequest: NSMutableURLRequest {
    // create and return the URL request
  }
}

The call using it that we’re trying to figure out looks like:

let request = Alamofire.request(PostRouter.Get(1))
  .responseJSON { response in
    // ... do stuff with the response
  }

For a whole demo project, go to GitHub.

The question is: How does Alamofire.request(PostRouter.Get(1)) end up calling PostRouter.URLRequest?

Computed Properties

First, what is PostRouter.URLRequest? It’s a property that gets evaluated using the code that’s provided when we need its value. That’s a computed property. When .URLRequest is called, the code provided to calculate its value gets run. If you call it again, the code to compute the value gets run again.

For read-only computed properties, Swift lets us drop the get keyword and the extra set of brackets. Presumably to make the code look prettier or save us from typing a few more brackets. So this code:

var URLRequest: NSMutableURLRequest {
  // create and return the URL request
}

does the same thing as this code:

var URLRequest: NSMutableURLRequest {
  get {
    // create and return the URL request
  }
}

That’s a property with a getter but no setter. In other words, a read-only property.

So we’ve figured that part out: when we call PostRouter.Get(1).URLRequest it’ll run the code within the get block to get the value to give us for that property.

Now that we know what happens if we call PostRouter.Get(1).URLRequest, let’s figure out how it’s getting called. It doesn’t appear anywhere in our code!

Let’s decompose this line: Alamofire.request(PostRouter.Get(1)), working from the inside out.

PostRouter.Get(1) just returns an instance of our enum for that case. So this would be the same as the line we’re trying to figure out:

let enumCase: PostRouter = PostRouter.Get(1)
Alamofire.request(enumCase)

That’s similar to calling an initializer to create an instance of a class. If we set up test code to just call PostRouter.Get(1) (comment out Alamofire.request(enumCase)) and put a break point in the var URLRequest block, then the URLRequest computed property never gets called. So PostRouter.Get(1) isn’t what’s causing the getter for URLRequest to get called.

URLRequestConvertible

Then it must be Alamofire.request(enumCase) that’s making it happen. Let’s dig into the Alamofire source code and see what .request(...) does:

public func request(URLRequest: URLRequestConvertible) -> Request {
  return Manager.sharedInstance.request(URLRequest.URLRequest)
}

To go to that declaration cmd-click on .request(...) in Xcode.

Ah ha! There’s the call to .URLRequest. But it looks a little cryptic. What’s going on there?

When we created our router we declared that each case would have a URLRequestConvertible value:

enum PostRouter: URLRequestConvertible

What’s a URLRequestConvertible that? Cmd-click to the rescue again! According to the Alamofire source code, URLRequestConvertible is a protocol. The only requirement for the protocol is that it has a read-only computed var property that is an NSMutableURLRequest:

public protocol URLRequestConvertible {
  /// The URL request.
  var URLRequest: NSMutableURLRequest { get }
}

That’s exactly like our URLRequest property in our router. Our router’s values conform with the URLRequestConvertible protocol. Which is why we could call Alamofire.request(enumCase) with our router enum cases.

How It Works

So here’s what happens:

  1. We create a router enum case for the API call we want to make. It must be a URLRequestConvertible
  2. Alamofire.request(...) takes that URLRequestConvertible and gets the URL request from it. Then it makes the network call for that request
  3. Any response handlers attached like Alamofire.request(...).responseJSON { ...} get called when the network call gets results (or times out or whatever)

While we’re using an enum, you don’t necessarily have to. You can use anything that conforms with URLRequestConvertible (which just means it has a URLRequest computed var) to make an Alamofire request. Classes, structs, or enums can be used. For example, here’s a struct that implements URLRequestConvertible:

struct URLRequestProvider: URLRequestConvertible {
  var URLRequest: NSMutableURLRequest {
    // don't use !'s (except for super-quick demos that will never be deployed)
    return NSMutableURLRequest(URL: NSURL(string: "http://jsonplaceholder.typicode.com/posts/1")!)
  }
}

And you can use it to make an Alamofire request:

Alamofire.request(URLRequestProvider())
  .responseJSON { ... }

And That’s All

Does that seem a little less magical now? Hopefully we’ve pulled back the curtain and demystified some of the “magic” that was in the last tutorial. As always, if you have any questions about anything in these tutorials please ask by email or comment below. If you’re stuck then plenty of other people probably are too.

If you’d like more Swift tutorials on topics like this one, sign up below to get them sent directly to your inbox.

Making your first Swift app that uses a web service can be overwhelming

It seems like every time you try to figure it out you just add more things to learn to your list: REST, Alamofire, parsing JSON, OAuth, App Transport Security, setting headers, …

But it doesn’t have to be confusing. In this free 5-part course, we’ll work through what you really need to know, one step at a time, building our skills as we go. (And get free Swift tutorials, sent straight to your inbox.)

iOS Apps with REST APIs Cover

With iOS Apps with REST APIs ebook I’ll teach you how to build Swift apps that get their data from web services without hundreds of pages about flatmap and Core Whatever. iOS Apps with REST APIs ebook is the book I wish I had on my first iOS contract when I was struggling to figure out how to get the API data showing up in the app I was building.

Other Posts You Might Like