Unless you are implementing your own network layer from scratch, Alamofire is the Swift network library of choice on iOS/OSX.
In a recent project I had to make a gzipped request to a service. Unfortunately this is not supported out of the box by Alamofire, so I started digging in the code of the library to see how I could achieve my goal in the nicest way possible.
Overview
ParmeterEncoding
Alamofire has a neat enum called ParameterEncoding.
This emum lets you specify how the parameters passed to Alamofire.request(...)
will be encoded in the body of the generate NSURLRequest
.
Not only that but, in some cases (like .JSON
) it will also add the appropriate Content-Type
header the HTTP request.
Pretty cool right?
Let’s take a look at the ParameterEncoding
.
As you can see there is a variety of encodings that are supported out of the box and the Custom
encoding let’s you specify your own.
This seemed exactly what I needed.
The Custom
constructor takes a function that takes two arguments (URLRequestConvertible, parameters: [String: AnyObject]?)
and returns a tuple
(NSURLRequest, NSError?)
. The type of the function is suspiciously similar to the type of the encode
function specified further down
in the enum.
This is no coincidence. In fact URLRequestConvertible
in the constructor of Custom
is a protocol that specifies that the first parameter is something that will produce a NSRULRequest
.
Whatever function you pass to the Custom
construct will become the encode(..)
function for your custom encoding. The encode(...)
function
will be called my Alamofire’s Manager
class when constructing the request.
Great! So since I wanted to GZIP my JSON encoded parameters I could have just done the following using 1024jp/NSData-GZIP to gzip my request.
This solution works, but what if I wanted to gzip some other encoding? I would have had to make a custom encoding for every other encoding I wanted to gzip, including other custom ones.
Could there be a more general solution? This is Swift so you can bet there is.
##ParamterEncoding Extension
The result I wanted to achieve was to just be able to create any encoding (.JSON
, PropertyList
, Custom
) and gzip it with no extra effort.
Something like this
If you take a look at the type of Alamofire.request
you will notice that the last parameter has type ParameterEncoding
. This in turn
would mean that the .gzipped
property I wanted would have to have the same type. Let’s start with that.
The computer property gzipped
will call another function to gzip … itself! Why? Because we want to take advantage of the fact that each encoding
already knows how to encode it’s own parameters. We just want to gzip the body of the request.
gzip(encoding:ParameterEncoding) -> ParameterEncoding
is a function that given a parameter encoding ( self ) will return another encoding. It will
return our custom one with the gzipped body and an appropriate “Content-Encoding” header.
The only thing left to do now is to write the last function gzipOrError
which has the same type as the return type of encode(...)
,
meaning (NSURLRequest, NSError?)
, and returns something compatible with the type of Custom
, meaning (URLRequestConvertible, parameters: [String: AnyObject]?)
Show me the code
Hopefully I have explained how this works without to much confusion. Grab the final version from this Gist.