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.
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
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
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.
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
Whatever function you pass to the
Custom construct will become the
encode(..) function for your custom encoding. The
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.
The result I wanted to achieve was to just be able to create any encoding (
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
(NSURLRequest, NSError?), and returns something compatible with the type of
(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.