Introduction

Of late, many programmers who develop for Windows/Linux have moved to iPhone because of it's runaway success. Among the most successful apps on the Apple AppStore, first comes games (yeah I can hear you, fart apps!!!). Next comes apps like Tweetie and others those consume a web service (REST or otherwise). Games are pretty difficult get started especially if you aren't a game programmer. However, developing iPhone applications that consume a web service is quite easy. In this article, I'll illustrate how to write a iPhone application to consume a web service. I'll take bit.ly's REST service as an example, and at the end, we will be developing a nice "bit.ly" wrapper in Objective-C. For those who are new to REST, it stands for Representational State Transfer. Head on to Wikipedia here for more details. The post itself is split into two parts, one focussing XML and the other JSON.
At the end of the second part, you can download the source code attached.

Bit.ly Documentation

Bit.ly, as you all know is a URL shortening service, that became popular all of a sudden when Twitter started using bit.ly as it's default URL shortening service over tinyurl.com. The REST documentation of bit.ly is available from Google code here.

Some Basics before we dirty our hands with real code

Authentication Types

bit.ly (and many such services) use a kind of HTTP authentication called Basic Authentication. In basic authentication, the username and password that is typed into the client is formatted as
: and the concatenated string is converted to "base64" encoding. This string is passed along with the HTTP Header usually in every API call that does some function which you have to normally log on to see.
There is one more type of authentication, oAuth, which stands from Open Authentication. As of now, bit.ly doesn't use oAuth. Explaining oAuth itself needs a separate article and is outside the scope of this article.

HTTP Request types

When you access a RESTful service, you either request data or post data. In most cases, your HTTP Request type is either a "GET" or a "POST". There are two more types of requests and they are, "PUT" and "DELETE". When to use what, is upto the designer of the RESTful service. You as a consumer, just follow the documentation.
In our case, bit.ly we will be using only "GET" methods.

The real code

You shouldn't be shocked to know that, accessing a RESTful service for data is just a matter of 10 line code.
NSString *longURL = @"http://mugunthkumar.com"
NSString *baseURLString =
@"http://api.bit.ly/shorten?version=2.0.1&longUrl=%@&login=bitlyapidemo&apiKey=";
NSString *urlString = [[NSString alloc] initWithFormat:@"%@%@",
baseURLString, longURL];
NSURL *url = [[NSURL alloc] initWithString:urlString];
NSString *result = [[NSString alloc] initWithContentsOfURL:url];
NSLog(result);
[url release];
[urlString release];
[result release];

Parsing the Result


The result which we "NSLogged" here could be either XML or JSON. In our case, bit.ly by default sends JSON formatted data, which is by far the most commonly used. JSON is lighter than XML for transferring the same amount of data. There are a lot of debate going along on which is good for data transfer. I personally prefer JSON. Of late, JSON is picking up over XML with the advent of JSON parsers. Objective C has a very robust JSON parser called json-framework. We will touch about them later in the next part of this article. The other kind of data format namely XML, is returned by bit.ly, only when you pass

format=xml

along with the URL as an additional parameter. For parsing XML, there are two parsers. One is NSXMLParser and the other is a faster libxml2. Though libxml2 is faster, use it on your iPhone app only when you are going to parse over 10MB of XML data. When your XML data is small (as in our case), the performance gap between NSXMLParser and libxml2 is very meagre. In case of bit.ly, the shorten api returns < 1KB of data. Most RESTful service return very little data (mostly in the order of few hundred kilo bytes) I prefer NSXMLParser for one reason. You code is cleaner than it would be if you use libxml2. In this article, I'll go take you through both ways of handling the data.

Parsing XML

[parser initWithContentsOfURL: url];
[parser setDelegate:self];

[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];

[parser parse];
[parser release];

Parsing XML data using NSXMLParser couldn't be simpler. You just have to create an object (parser) of type NSXMLParser, initialize it and call parse.

Things to note

However, there are a couple of things to note.

1) You can initialize the parser object either with NSURL or with NSData. Both methods work equally well.
2) You OUGHT to set the delegate to self. Otherwise there is no way for the NSXMLParser to notify you of events.
3) The next three lines are optional. You usually set it to YES if you want to get notified of those events as well.
4) The call to [parser parse] is blocking. This means, it will not return until the complete content is parsed. So, you can (and should) release any associated memory at the next line.

Callbacks from NSXMLParser

NSXMLParser has around 14 callback methods. But it's enough if you implement just three of them. They are,

parser:didStartElement:namespaceURI:qualifiedName:attributes:
parser:didEndElement:namespaceURI:qualifiedName:
parser:foundCharacters:

The didStartElement is called when the XMLParser encounters a opening XML element. You usually initialize temporary variables and read attributes if any in this function. In case of bit.ly, you just have to read the "shortUrl" element. Just handling this element alone will do.

ShortURL from bit.ly

ShortURL from bit.ly

Declare the following NSStrings, currentShortURL, actualShortURL and currentElement.
Write the following code into the didStartElement Block.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
currentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:@"shortUrl"]) {
currentShortURLString = [[NSString alloc] init];
}

Now, in the foundCharacters block, write the following code.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:@"shortURL"]) {
[currentShortURLString appendString:string];
}

In the didEndElement block write,
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"shortURL"]) {

actualURLString = currentURLString;
}

Now when the parsing ends, just after the [parser release] function, actualShortURLString will contain the shortened URL.


End of story. If you couldn't follow the code in this blog post, you can always download the source code attached (in next part). For more detailed information on parsing using NSXMLParser follow this article.

Parsing JSON


Parsing JSON is much simpler than XML. In fact, I hate to call it as "parsing" as you don't even have to write a parser!!! By using the open source json-framework kit for iPhone you can easily "convert" a JSON string into a NSDictionary. Now let's have a look at the code.

JSON Parsing Code

JSON Parsing is far much simpler than XML. Infact, the code attached below uses JSON.

Parsing the bitly information is as simple as writing these three lines of code.
SBJSON *jsonParser = [SBJSON new];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *dict = (NSDictionary*)[jsonParser objectWithString:jsonString];

The return string is a dictionary of key value pairs.To read a value, you can call objectForKey function within NSDictionary.

In most cases, including bit.ly, JSON return strings always contain other dictionaries nested within itself. To read a value within a dictionary, just nest your calls  like this.
NSString *shortURL = [[[dict objectForKey:@"results"]
objectForKey:f_longURL]
objectForKey:@"shortUrl"];

Source Code and Documentation

The source code and documentation on how to use this is explained in post 2.

Follow me on Twitter

  • Simon

    The link for Part 2 is broken.

    • http://intensedebate.com/people/mugunthkumar mugunthkumar

      Pardon me… The part 2 of the article is still in Draft…
      Do check back in a couple of weeks… I'll upload the src code as well..

      • Goran

        Is it possible for you to upload source now, and article later? I would be very interesting to play with code.

        • http://intensedebate.com/people/mugunthkumar mugunthkumar

          Updated the post with the source code… :)

  • Pingback: Tweets that mention Consuming a RESTful Service (bit.ly) in an iPhone Application (1/2) | Mugunth Kumar's Blog -- Topsy.com

  • Pingback: bit.ly wrapper for Objective-C/iPhone | Mugunth Kumar's Blog

  • http://polprav.blogspot.com/ Polprav

    Hello from Russia!
    Can I quote a post in your blog with the link to you?

    • http://intensedebate.com/people/mugunthkumar mugunthkumar

      Sure.

  • http://blog.fatcow.com/custom-iphone-icons-to-be-or-not-to-be/ 2012 Iphone Icons

    Your post is a great source of knowledge. I am the beginner,so please bear with me.

  • Hatrantuekhuong

    Can you tell me more about how many ways can an iphone app connect to web service app? Thanks so much. I do hope you answer me soon because I have a problem for my project which interdepends on it. Please!