UPDATE: 28th Sep 2015

When I wrote this post and the code in it I was just starting out with Swift. Since writing it I’ve made some signifcant improvements to our Loot API wrapper that I’m sure you’ll see missing from the code below. For example, the Result that’s passed back to the handler() is much better as an enum. This is of course because you can associate data with cases (.Success(tokenString)). I’ll be writing a post in the coming days to talk about how my approach to writing an API wrapper has changed and improved.

I’ve been building a wrapper around our API at Loot in Swift. I wanted it to be completion handler based. And, for two reasons, I also knew that I wanted to define the parameters that get passed into the handler, as a type:

  • Brian Gesiak’s talk at UIKonf. Brian gave a great talk about writing APIs, and one of his points was that having parameter types makes changing the API in the future, easier, and gives more power (deperaction warnings and more)
  • Because I want to be able to have a local variable for the handler params which I can change in the function body and then return to the handler at the end. Here’s what that looks like:
typealias CreateAccountResult = (code: Response, token: String, errors: [Error]?)

static func createAccount(email: String, password: String, handler: CreateAccountResult -> ()) {
        if !self.deviceHasInternetConnection() {
            handler((result: .NetworkUnreachable: token: nil, errors: nil))
        let params = [ "email" : email, "password" : password] as NSDictionary
        let request = self.requestWith(url: userEndpoint, method: "POST", json: NSJSONSerialization.dataWithJSONObject(params, options: nil, error: nil)!)
        NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
            var result: CreateAccountResult = (code: .ReposponseError, token: nil, errors: nil)
            if let httpResponse = response as? NSHTTPURLResponse, 
                json = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? NSDictionary {
                    if httpResponse.statusCode == 200, let token = json.objectForKey("token") as? String {
                    	// ** CHANGE HERE **
                        result = (code: .Success, token: token, errors: nil)
                    } else if httpResponse.statusCode == 404 {
                        var createAccountCodes: [CreateUserAccountCode]?
                        if let codeNumbers = json.objectForKey("codes") as? Int {
                            createAccountCodes = [CreateUserAccountCode]()
                            for code in codeNumbers {
                                if let codeAsEnum = CreateUserAccountCode(rawValue: code) {
                        // ** CHANGE HERE **
                        result = (code: .Error, token: nil, errors: createAccountCodes)
            // ** PASS BACK HERE **

SO. I knew that I wanted to define the params I pass into the handler function as a type. And I initially went with what Chris Eidhof said about starting with a tuple (see “What should I use?” at the bottom), even though Brian spoke about using a struct.

After writing the wrapper with tuples for defining the handler params, I found these annoying things, and reasons that solidify the idea of using of a struct instead:

  • You can’t declare a parameter name for a tuple in a closure if it’s the only parameter. Which means:
  • Code completion is crappy with tuples
    • When you write the function call, tab to the handler, then hit return, you then also have to write local variable name for the tuple. I feel that having a name, that the user can change, pre-written is important for clarification of what the tuple actually is.
    • You (sometimes) don’t get code completion when accessing params in the tuple
  • The variables in the tuple are just that. Variables. They can be changed. This not cool and opens room for bugs.
  • This ones not a biggy, but with a tuple’s variables can be accessed by index, so if you re-order params in the tuple for whatever reason, it will lead to errors for it’s users.

For these reasons I’m going to go with structs. Another cool thing with structs: you can give them init methods that are private to your API class thus stopping other classes for even making them!

Thoughts, tips, improvements and suggestions are always welcome with me. Ping me on Twitter.

Inspirations from this post

This post and the feeback from my colleague Jacek have inspired me to think about another post on parsing the returned data from the API (JSON in our case) and about which classes take responsibility of parsing which parts of the response.

  • Should the API class just make the request and return the NSData to a parser class?
  • Who should parse what?
  • Should the User class be responsible for pulling out it’s own data from the JSON (feels good to me)?
  • What if some data, such as a token for the logIn() function, is returned from the server?
  • What parses the token, and what parses the user?
  • Should the API class return an error enum if the expected token is not found in the logIn() function?
  • Perhaps some mix where the API makes sure the returned data is JSON and that the token is there, then it passes the rest of the JSON to the User class?

I’ll add a link here to the post I write on this topic later.