Introducing HTTPRiot - Easily Consume REST Resources on the iPhone and OS X

—Saturday, July 11 2009

If you’ve ever tried to do networking with Foundation you know that wrestling with NSURLConnection and NSURLRequest can be painful. Thankfully, we’ve seen a few third party tools step up to alleviate some of this pain. I want to introduce you to a couple of those tools and show you what I’ve been working on as well.

HTTPRiot logo

UPDATED: Fixed the permission issue on the download link

The current crop of tools

There are some excellent HTTP libraries available for the iPhone and OS X. So why do we need another one? Balance. There are two particularly popular libraries that I’m going to talk about: ASIHTTPRequest and ObjectiveResource. I’ll explain the benefits and tradeoffs of each and also explain where HTTPRiot fits in to this equation.

ASIHTTPRequest

ASIHTTPRequest is a highly flexible lower level tool (relative to HTTPRiot & ObjectiveResource). It can do a lot of things and do them well. Besides the basic GET, POST, PUT and DELETE you can also upload files, post form encoded data, handle basic authentication and a host of other really nice things. Not to mention it can handle synchronous and asynchronous requests–something HTTPRiot and ObjectiveResource can’t do. This library is all about flexibility and this flexibility doesn’t take away from how easy it is to use. This is code you should definitely have in your bag of tricks when you’re in need of an all purpose HTTP library.

The tradeoff for ASIHTTPRequest is that it can’t automatically convert XML and JSON. There is also no mechanism for setting default configuration options which results in you having to configure things like delegates and selectors for every asynchronous request. To be fair, ASIHTTPRequest was never meant to be used this way, thus I would take these tradeoffs with a grain of salt.

ObjectiveResource

If you’ve ever used ActiveResource with Rails you’ll probably be familiar with ObjectiveResource’s style. ObjectiveResources is a high-level library that does a lot of behind the scenes work. It’s built specifically to consume REST resources. It can convert to and from JSON and XML (ASIHTTPRequest can’t) and it will automatically initialize models and do all sorts of other work for you. This makes it a great fit for working in conjunction with a Rails app.

The tradeoff of ObjectiveResource is that it doesn’t handle XML and JSON that’s not produced by Rails well. I’m not sure what kind of results you’d get if you fed it something like Govtrack’s bill data. ObjectiveResource is also a big library with a lot of moving parts. In addition to the networking code, the library also includes ObjectiveSupport, a nice library in itself that’s loosely based on ActiveSupport.

One final thought about ObjectiveResource—there are a lot of methods added to NSObject. Apple doesn’t explicitly say not to do this, but they do warn you of the consequences:

“You can define categories that add methods to the root class, NSObject. Such methods are available to all instances and class objects that are linked into your code. Informal protocols—the basis for the Cocoa delegation mechanism—are declared as categories on NSObject. This wide exposure, however, has its dangers as well as its uses. The behavior you add to every object through a category on NSObject could have consequences that you might not be able to anticipate, leading to crashes, data corruption, or worse.”

With all that being said, ObjectiveResource is definitely worth checking out. I know a few people who are using it and love it.

HTTPRiot

Like ObjectiveResource, HTTPRiot was inspired by its Ruby counterpart: John Nunemaker’s httparty. Hence the name. HTTPRiot serves as a balance between ASIHTTPRequest and ObjectiveResource. You get a certain amount of flexibility and a higher level api. Like ASIHTTPRequest, you can send GET, POST, PUT, and DELETE requests, also like ObjectiveResource the XML or JSON response will automatically be converted to an Objective-C type (NSArray or NSDictionary).

The tradeoff with HTTPRiot is that it makes no attempt to convert the data further or automatically compose instances of other objects for you. It gives you the data and lets you do what you want with it. This means that you must be aware of the data you receive because it’s up to you to decide what to do with it after it’s been converted to a native type. For instance, if two request originate from the same model they will both use the same delegate methods to handle the response. It’s up to you to decide what’s what.

Some examples

Some quick examples to give you an idea of how you use HTTPRiot.

GET Request: Reads JSON from the server.

[Person getPath:@"/people" withOptions:nil object:nil];

POST Request: POSTs the body set in options to the server.

NSDictionary *options = [NSDictionary dictionaryWithObject:[foo JSONRepresentation] forKey:@"body"];
[HTTPRiotRestModel postPath:@"/person" withOptions:options error:nil];

Setting default options: You can subclass HRRestModel and set default options like basic auth, headers, params, etc. Every request you make from MyModel will use these default options.

@implementation MyModel
+(void) initialize {
    [self setBasicAuthWithUsername:@"justin" password:@"pass"];
    [self setDefaultHeaders:[NSDictionary dictionaryWithObject:@"Some Header Value" forKey:@"My-Header"]];
}
@end

Implementing the delegate methods

You’ll need to implement a few delegate methods to deal with the responses. I’ll explain why I settled on this approach in another post, but for now here is sample of what you’ll have:

- (void)restConnection:(NSURLConnection *)connection didReturnResource:(id)resource object:(id)object {
    //resource contains the NSDictionary or NSArray version of the XML or JSON you requested
    for(id item in resource) {
        //Do something with your data
    }
}

- (void)restConnection:(NSURLConnection *)connection didReceiveError:(NSError *)error response:(NSHTTPURLResponse *)response object:(id)object {
    //Recieved a bad status code 404, 500, etc.
}

Summing up

All three libraries have a job they are well suited for. Hopefully I’ve given you an idea of what to expect with each one. On a final note regarding HTTPRiot, it is a young library so there will likely be bugs along the way. If you spot one, cease development and report it to the proper authorities.