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.