PMHTTP, a REST networking library for Swift/Obj-C

Datetime:2016-08-23 01:55:48          Topic: Swift  REST           Share

Today we’re releasing a networking library for Swift/Obj-C that we’ve been using for the past half year. It’s called PMHTTP , and it focuses on REST APIs and JSON (using PMJSON ), though not exclusively. It was designed for Swift first, but with full Obj-C compatibility.

We really like NSURLSession and we think it’s a great API for doing networking. We believe that most people who look for third-party networking libraries for iOS/macOS should probably just be using NSURLSession. But when writing a large app, we find ourselves writing a lot of boilerplate around NSURLSession to handle common cases, such as decoding JSON or interpreting status codes. So we wrote PMHTTP to handle all of this for us. PMHTTP does not expose all of the functionality provided by NSURLSession, but it provides everything we need, such as strong support for REST, application/x-www-form-urlencoded and multipart uploads, and JSON decoding.

There are other third-party networking libraries out there, but none of them really fit our needs. We never even considered AlamoFire because we need Obj-C compatibility, and we’re not happy with AFNetworking for a few reasons, such as dynamic typing and the fact that it does most of its work on the main thread. PMHTTP works with both Swift and Obj-C, is strongly-typed, and it doesn’t use the main thread for anything unless explicitly instructed to do so. This makes it easy to take all of our data parsing and do it in the background, and only hop on the main thread when we want to update our UI with the results.

The design goals of PMHTTP are:

  • Be as Swift-like as possible while retaining Obj-C compatibility.
  • Speed, with an emphasis on being concurrent by default.
  • Thread safety wherever it makes sense.
  • Explicitness and type safety. For example, PMHTTP doesn’t auto-detect the return type but requires you to declare what response format you’re expecting.
  • Correctness, which includes avoiding surprising behavior.

And some of the more notable features of PMHTTP are:

  • Requests can define parse handlers that execute asynchronously separately from the completion block, and requests can be canceled while parsing and the completion block sees the correct result.
  • Strongly-typed results.
  • Thread safety.
  • Configurable automatic retrying of failed requests when safe.
  • multipart/form-data , application/x-www-form-urlencoded , and JSON upload support.
  • Built-in request mocking support without using method swizzling.

The last one is one of my favorite features. With it, I can install a mock globally for a given URL, or I can mock a single request. This makes it really easy to test out new functionality before the backend support is ready, and it’s also great for unit testing. And the mocking doesn’t use method swizzling (unlike some other mocking libraries) so it’s perfectly safe to use even in apps submitted to the App Store.

In PMHTTP, requests are objects, similar to NSURLRequest, that can be used repeatedly to create tasks. The API is designed to allow for a functional-style chain to create and execute a request. An sample request might look like:

HTTP.request(GET: "user")
    .parseAsJSONWithHandler({ try User(json: $1) })
    .with({ $0.userInitiated = true })
    .performRequestWithCompletion(onQueue: .mainQueue()) { (task, response) in
        switch response {
        case .Success(_, let user):
            // ...
        case .Error(_, let error):
            // ...
        case .Canceled:
            // ...
        }
}

In this example the code that parses the JSON into a User object runs in the background, and then the completion block runs on the main queue. Having this built-in to the library is especially useful because you can cancel the task after the networking portion is finished, while it’s parsing the response, and the completion block will still receive the  .Canceled response. This should be really useful if you’ve ever found yourself writing code like:

self.task?.cancel
var task: NSURLSessionDataTask?
task = urlSession.dataTaskWithRequest(request) { [weak self] (data, response, error) in
    if let data = data, user = User(data: data) {
        dispatch_async(dispatch_get_main_queue()) {
            guard let this = self where this.task === task
                else { return }
            this.task = nil
            // process the data
        }
    } else { /* ... */ }
}
self.task = task
task.resume()

There’s a lot more to the library too, including asynchronous streamed multipart uploads, basic authentication, swappable environments, and more. You can find out more about what the library supports, including more detailed explanations of the various APIs and features, at the PMHTTP GitHub repo .

Kevin Ballard ( @eridius ) is an iOS Developer at Postmates.

Want to join Kevin and the Postmates Engineering team in building more cool stuff like this?Apply here.





About List