Custom Headers With Alamofire 4 and Swift 3
October 21, 2016 - Swift 3.0

I previously wrote about adding custom headers to Alamofire 3 calls. Let’s figure out how to handle custom headers in Swift 3 and Alamofire 4.

When dealing with custom headers in Alamofire requests you might need to include a header for all of your API calls or just for a single call. We’ll show how to handle both of those scenarios and the four different ways that headers can be included in Alamofire calls.

The custom headers we set up previously were an API key and JSON accept header for the Mashape API:

  • X-Mashape-Key: MY_API_KEY
  • Accept: application/json

Here’s a curl statement with those headers included:

curl --get --include 'https://mashape-community-urban-dictionary.p.mashape.com/define?term=smh' \
-H 'X-Mashape-Key: MY_API_KEY' \
-H 'Accept: application/json'

Mashape has tons of free APIs that you can use play with to build your skills. Sign up for a free account to get an API key to use wherever you see MY_API_KEY in this tutorial. You can see the documentation for the Urban Dictionary API in Mashape.

This tutorial has been written using Swift 3.0, Xcode 8.0, and Alamofire 4.0.

Adding a Header to a Single Request

When creating a request, we can pass the headers as an argument. Here’s how we’d do that for our two headers:


let headers: HTTPHeaders = [
  "X-Mashape-Key": MY_API_KEY,
  "Accept": "application/json"
]

Alamofire.request("https://mashape-community-urban-dictionary.p.mashape.com/define?term=smh", headers: headers)
  .responseJSON { response in
  debugPrint(response)
}

HTTPHeaders is just a dictionary of strings:


public typealias HTTPHeaders = [String: String]

This way of including headers is useful when you only need to pass a header for a single call. For the headers we need for Mashape there are better options that will avoid having to add the headers to each request.

To make sure your headers are being sent, you can use debugPrint to inspect the request:


let request = Alamofire.request("https://mashape-community-urban-dictionary.p.mashape.com/define?term=smh", headers: headers)
  .responseJSON { response in
  debugPrint(response)
}
debugPrint(request)

Which will show you the equivalent curl statement:


curl -i \
  -H "Accept-Language: en;q=1.0" \
  -H "X-Mashape-Key: MY_API_KEY" \
  -H "User-Agent: GrokHeaders/1.0 (com.grokswift.GrokHeaders; build:1; iOS 10.0.0) Alamofire/4.0.1" \
  -H "Accept: application/json" \
  -H "Accept-Encoding: gzip;q=1.0, compress;q=0.5" \
  "https://mashape-community-urban-dictionary.p.mashape.com/define?term=smh"

Session Custom Headers

If you need to specify a header for all of the calls you make, then create a custom session configuration and add it there. This shouldn’t be used for authentication. An example of when you might use it is for API version headers:


// get the default headers
var headers = Alamofire.SessionManager.defaultHTTPHeaders
// add your custom header
headers["API-Version"] = "2.0"

// create a custom session configuration
let configuration = URLSessionConfiguration.default
// add the headers
configuration.httpAdditionalHeaders = headers

// create a session manager with the configuration
let sessionManager = Alamofire.SessionManager(configuration: configuration)

// make calls with the session manager
sessionManager.request("https://mashape-community-urban-dictionary.p.mashape.com/define?term=smh")
  .responseJSON { response in
  debugPrint(response)
}

As before, if you need to check the headers are being added correctly use debugPrint to check the request:


let request = sessionManager.request("https://mashape-community-urban-dictionary.p.mashape.com/define?term=smh")
  .responseJSON { response in
  debugPrint(response)
}
debugPrint(request)

Add Headers to URLRequest

When creating Alamofire requests you can provide a URLRequest instead of passing in the URL as a string like we did above. When creating that request you can add headers. Here’s an example of creating an Alamofire request using a URLRequest:


if let url = URL(string: "https://mashape-community-urban-dictionary.p.mashape.com/define?term=smh") {
  var urlRequest = URLRequest(url: url)
  urlRequest.httpMethod = HTTPMethod.get.rawValue
  
  urlRequest.addValue(MY_API_KEY, forHTTPHeaderField: "X-Mashape-Key")
  urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
  
  Alamofire.request(urlRequest)
    .responseJSON { response in
      debugPrint(response)
  }
}

Use urlRequest.addValue to avoid replacing an existing headers. If you prefer, you can get the current headers, add your new values, then set them:


if let url = URL(string: "https://mashape-community-urban-dictionary.p.mashape.com/define?term=smh") {
  var urlRequest = URLRequest(url: url)
  urlRequest.httpMethod = HTTPMethod.get.rawValue
  
  var headers: HTTPHeaders
  if let existingHeaders = urlRequest.allHTTPHeaderFields {
    headers = existingHeaders
  } else {
    headers = HTTPHeaders()
  }
  headers["X-Mashape-Key"] = MY_API_KEY
  headers["Accept"] = "application/json"
  urlRequest.allHTTPHeaderFields = headers
  
  let request = Alamofire.request(urlRequest)
    .responseJSON { response in
      debugPrint(response)
  }
  debugPrint(request)
}

Since allHTTPHeaderFields is optional we need to check that it exists and create a new dictionary if it doesn’t.

If you’re using a router to create each URLRequest then this method can work well for adding your headers, including auth headers. If you’re not using a router then the RequestAdapter below might be easier to implement.

HTTPMethod.get.rawValue uses the HTTPMethod enum defined in Alamofire instead of specifying “get” as a string. Since the enum is defined as a string we can use the rawValue to get the string for each method.


public enum HTTPMethod: String {
  case options = "OPTIONS"
  case get     = "GET"
  case head    = "HEAD"
  case post    = "POST"
  case put     = "PUT"
  case patch   = "PATCH"
  case delete  = "DELETE"
  case trace   = "TRACE"
  case connect = "CONNECT"
}

It’s good practice to use those values instead of typing in get or whatever method you’re using as a string.

Request Adapter

Alamofire 4.0 added a RequestAdapter protocol. If you set up a request adapter then it’ll get applied to all of the requests made in your session.

To use a request adapter, first create one. In the adapt function we’ll add the headers to the request:


class MashapeHeadersAdapter: RequestAdapter {
  func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
    var urlRequest = urlRequest
    
    urlRequest.setValue(MY_API_KEY, forHTTPHeaderField: "X-Mashape-Key")
    urlRequest.setValue("application/json", forHTTPHeaderField: "Accept")
    
    return urlRequest
  }
}

Then, similar to setting headers for a session, we need to create a custom session manager and add the RequestAdapter to it:


// get a session manager and add the request adapter
let sessionManager = Alamofire.SessionManager.default
sessionManager.adapter = MashapeHeadersAdapter()

// make calls with the session manager
let request = sessionManager.request("https://mashape-community-urban-dictionary.p.mashape.com/define?term=smh")
  .responseJSON { response in
    debugPrint(response)
  }
debugPrint(request)

This approach is useful for handling headers like authorization tokens. It’s a good choice especially if you’re not already explicitly creating a URLRequest for each call.

And That’s All

Now we’ve seen the numerous ways to add HTTP headers to an Alamofire request. You can add headers to a single call, a whole session (using a custom configuration), as part of a URLRequest, or using a fancy new RequestAdapter.

Here’s the code: Custom HTTP Headers with Swift 3.0 and Alamofire 4.0

Over the next while I’ll be working through how to update more networking code to Swift 3.0, like how to handle authentication. If there’s something specific you want to see, leave a comment or email me.

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

Want more Swift tutorials like this one?

Sign up to get the latest GrokSwift tutorials and information about GrokSwift books sent straight to your inbox

Other Posts You Might Like