Tommaso Piazza

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.

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.

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.

extensionParameterEncoding{vargzipped:ParameterEncoding{returngzip(self)}privatefuncgzip(encoding:ParameterEncoding)->ParameterEncoding{// think of gzipEncoding as a function that first encodes then gzips// this is function compositionletgzipEncoding=self.gzipOrError•encoding.encodereturnParameterEncoding.Custom(gzipEncoding)}}

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]?)

extensionParameterEncoding{vargzipped:ParameterEncoding{returngzip(self)}privatefuncgzip(encoding:ParameterEncoding)->ParameterEncoding{// think of gzipEncoding as a function that first encodes then gzips// this is function compositionletgzipEncoding=self.gzipOrError•encoding.encodereturnParameterEncoding.Custom(gzipEncoding)}privatefuncgzipOrError(request:NSURLRequest,error:NSError?)->(NSMutableURLRequest,NSError?){letmutableRequest=request.mutableCopy()as!NSMutableURLRequestiferror!=nil{return(mutableRequest,error)}vargzipEncodingError:NSError?=nildo{letgzippedData=trymutableRequest.HTTPBody?.gzippedData()mutableRequest.HTTPBody=gzippedDataifmutableRequest.HTTPBody!=nil{mutableRequest.setValue("gzip",forHTTPHeaderField:"Content-Encoding")}}catch{gzipEncodingError=errorasNSError}return(mutableRequest,gzipEncodingError)}}

Show me the code

Hopefully I have explained how this works without to much confusion. Grab the final version from this Gist.