RestConnection

This is the first post in a series on accessing RESTful web services from the iPhone.
The example project used in this post can be downloaded here.


REST

Unlike many other types of web services, all RESTful web services provide a uniform set of actions irrespective of their data entities. Every resource, or "noun", in a RESTful web service has the same set of methods, or "verbs", to do any and everything to that resource.

Resources are specified using HTTP URIs.  www.myurl.com/people could represent a collection of persons, while www.myurl.com/people/joebob would represent a single person. I should note that normally you would have your resources identified by a unique id, such as SSN or account number, and not by something like a name. That is a different discussion however.

The HTTP methods POST, GET, PUT, and DELETE map to basic CRUD (Create, Read, Update, and Delete respectively) very well. Non RESTful services may have methods like CreateWidget, UpdateTheThing, or RetrieveMySearchStuff. Under these schemes you would invoke different "verbs" depending on the "noun" you're handling.

Using our example URI above, if we do a GET on /people we would expect to get back all the persons in the collection. Doing a GET on /people/joebob should only return one person, joebob.


REST + iPhone

One of the great things about REST web services is that consuming them on the iPhone is easy. NSURLConnection provides all the functionality required to connect to a URI and transfer information in and out it. By simply building an NSURLRequest, you can perform all your CRUD operations via the NSURLConnection. We are going to simplify access to the NSURLConnection class through composition and object delegation. 

In any non-trivial client application, there are multiple objects in your data model. RestConnection will help to compose the commonalities of accessing those objects. It will also provide a way to persist information associated with the request; the NSURLRequest, NSURLResponse, and the response data.


The Example

I'm not necessarily a proponent of Google, however they provide some very useful web technologies that are very easy to use. For this article I'll be using their non-javascript AJAX search api. Though the RestConnection class will support all HTTP methods, I'll only be showcasing the GET functionality for now. We'll evolve the class as the articles progress.

In keeping with the classic search paradigm I'll keep the example very simple. The end result will look like screenshot on your right. The text field at the top allows search text to be entered and the text view on the bottom displays the results. You can grab the code here if you haven't already.

As will all future examples, this one assumes that you have an iPhone development environment already setup. If you don't then start here. This also assumes that you have a basic understanding of iPhone development. Some of the things I talk about may not make sense if you do not.

searchwindow

The Project

On top of a bare bones iPhone window project, there are the following additions; a view controller and accompanying xib, the RestConnection class, and the RestConnectionDelegate protocol.

I'm only going to be talking about the interesting parts of the codes in this article. All that I'm going to say about the app delegate is that it is standard glue code, nothing special going on in there. Lets focus on the RestConnection and it's client, SearchResultsViewController.


RestConnection

RestConnection is a lightweight composition class. It houses an NSURLRequest, NSURLResponse, NSData, and (while loading data) an NSURLConnection. It allows you to specify a base URL string that can be prepended to all requests it handles. It also provides a delegate for callbacks of interesting connection events. Lastly it provides methods for both loading url requests and accessing the current state of the RestConnection; the last request, last response, and last response data.

The method initWithBaseURL is the designated initializer for the class. Calling init will cause this method to be called with an empty base URL. Most of the time when dealing with web services there is a root URL (i.e. domain or ip address) that a collection of services will have in common. The base URL is a convenience for dealing with collections of endpoints so you can easily specify relative URLs in your requests.

Once the class is created, you can set an optional delegate. The delegate will receive callbacks about interesting connection events. All of the information passed to the delegate are accessible via properties as well.

Once a RestConnection instance has been initialized, it can begin requesting data using NSURLRequests with the performRequest method. RestConnection uses NSURLConnection to perform all the requesting. An instance of NSURLConnection is created every time performRequest is executed and destroyed after the request is completed. NSURLConnectionDelegate method callbacks drive the object after this.  The interesting ones are either passed on to the RestConnection delegate or used to accumulate the connection data.

Please note that an instance RestConnection is only meant to retrieve a single resource at a time. Attempting to call performRequest while a request is already pending can have unexpected consequences. A future version of this class will prevent this from being allowed. Creating multiple instances of RestConnection would allow this type of behavior. 


SearchResultsViewController

This view controller drives most the example. First, when the view loads, it creates an instance of the RestConnection and manages it for the lifecycle of the view controller.
- (void)viewDidLoad {
											    [super viewDidLoad];
											    restConnection = [RestConnection new];
											    restConnection.baseURLString = @"http://ajax.googleapis.com/ajax/services/search/";
											    restConnection.delegate = self;
											}

Here you can note that it instantiates a RestConnection and initializes its properties. The base URL is set which will cause subsequent requests to be relative to that URL string. The delegate is also set to the view controller's instance, this will allow it to keep tabs on the request as the it progresses.

Whenever the user enters something into the search field, the client needs to build a request and retrieve the results. Lets take a look at the method that gets called in the text field's Did End On Exit action.

- (void)performSearchForText:(NSString *)searchText
											{
											    NSString *text =
											        [searchText stringByAddingPercentEscapesUsingEncoding:
											        NSASCIIStringEncoding];
											
											    NSString *urlString = [NSString stringWithFormat:@"web?v=1.0&q=%@", text]; 
											    [restConnection performRequest:
											     [NSURLRequest requestWithURL:
											      [NSURL URLWithString:urlString]]];
											}

Here the view controller is formatting a URL component with the user's search string and passing it off to the RestConnection to begin loading the data. The data will be loaded asynchronously with delegate callbacks being performed on the same thread from which performRequest was called, in this case the main thread.


RestConnectionDelegate

The protocol RestConnectionDelegate contains 3 methods that are used as callbacks for various phases of loading a URL's contents. This protocol is declared in the interface of the view controller as such:

@interface SearchResultsViewController : UIViewController <RestConnectionDelegate> {

For the example, the delegate methods are used for a few different purposes.

willSendRequest is used to handle showing in the loading UI, a UIActivityIndicator
didReceiveResponse simply logs the response to the console
finishedReceivingData displays the connection's response text and hides the loading UI


Conclusion

This post touched on a lot of different concepts, even though the example's functionality is minimal. Such is life as a developer, a lot of work for very little return. Well not when you consider what is being done under the covers. 

Hopefully this can help you be more productive on your projects. Certainly in future posts the RestConnection class will contain more functionality. We'll even see how we can abstract RestConnection away completely and use the concept of data requests in your client code.

You can find the next post in this series here.

Until the next time, enjoy.


Even your worst day has a lesson to learn.