RESTful
Services

Modified

Disclosure   

The base application for the following example was taken from iPhone SDK Development by Dudney and Adamson, ISBN 978-1-93435-625-8.

REST overview from http://en.wikipedia.org/wiki/Representational_State_Transfer

Download

Overview

REST is not a formal standard but a philosophy, one well-suited for mobile devices because RESTful server resources tend to place lighter weight demands on the mobile client.

Alternatives to REST include Web-services using SOAP.

Proponents of REST argue that the Web's scalability and growth are a direct result of a few key design principles:

  • Application state and functionality are abstracted into resources
  • Every resource is uniquely addressable using a universal syntax for use in hypermedia links
  • All resources share a uniform interface for the transfer of state between client and resource, consisting of
  • A protocol which is:

    The following table associates several common HTTP verbs with similar database operations, however the meaning of the HTTP verbs do not correspond directly with a single database operation. For example, an HTTP PUT is used to set the value of a resource and may result in either a creation or replacement as needed.

    HTTP CRUD
    POST Create
    GET Read
    PUT Update, Create
    DELETE Delete

    When used RESTfully, HTTP is stateless. Each message contains all the information necessary to understand the request when combined with state at the resource. As a result, neither the client nor the server needs to remember any communication state between messages. Any state retained by the server must be modeled as a resource.

     

Twitter search using RESTful service and NSXMLParser

The example implements a simple client that, given a user name, finds an associated twitter text and url.

Twitter provides access to their database records such as Tweets using a RESTful approach, the essence being that:

The following URL:

http://twitter.com/users/show.xml?screen_name=ray

generates the XML response below. Try the URL!

<?xml version="1.0" encoding="UTF-8"?>
<user>
	<id>12801</id>
	<name>Ray Garraud</name>
	<screen_name>ray</screen_name>
	<location>26.086118, -80.373616</location>
	<description>Entrepreneur, Writer, Father of 3. Pursuing ideas and activities that create value.</description>
	<profile_image_url>http://a1.twimg.com/profile_images/636002114/rayray_normal.jpg</profile_image_url>
	<url>http://raymondgarraud.com</url>
	<protected>false</protected>
	<followers_count>3856</followers_count>
	<profile_background_color>C6E2EE</profile_background_color>
	<profile_text_color>663B12</profile_text_color>
	<profile_link_color>1F98C7</profile_link_color>
	<profile_sidebar_fill_color>DAECF4</profile_sidebar_fill_color>
	<profile_sidebar_border_color>C6E2EE</profile_sidebar_border_color>
	<friends_count>2892</friends_count>
	<created_at>Fri Nov 17 04:41:35 +0000 2006</created_at>
	<favourites_count>195</favourites_count>
	<utc_offset>-18000</utc_offset>
	<time_zone>Eastern Time (US &amp; Canada)</time_zone>
	<profile_background_image_url></profile_background_image_url>
	<profile_background_tile>false</profile_background_tile>
	<notifications></notifications>
	<geo_enabled>true</geo_enabled>
	<verified>false</verified>
	<following></following>
	<statuses_count>8309</statuses_count>
	<lang>en</lang>
	<contributors_enabled>false</contributors_enabled>
	<status>
		<created_at>Sat Jan 16 21:21:40 +0000 2010</created_at>
		<id>7839584681</id>
		<text>Sudden gust of wind / footsteps on the promenade / a little faster / © / #Haiku #FB</text> 
		<source>&lt;a href=&quot;http://www.yelp.com/&quot; rel=&quot;nofollow&quot;&gt;Yelp&lt;/a&gt;</source>
		<truncated>false</truncated>
		<in_reply_to_status_id></in_reply_to_status_id>
		<in_reply_to_user_id></in_reply_to_user_id>
		<favorited>false</favorited>
		<in_reply_to_screen_name></in_reply_to_screen_name>
		<geo/>
		<contributors/>
	</status>
</user>

SimpleTwitterClient

The application:

  1. performs a HTTP GET using the text field entry as the Twitter user name.
     
  2. retrieves the XML response from the Twitter server as a string tweetsData
     
  3. parses the XML in tweetsData using NSXMLParser, constructing a dictionary with the three elements:
    1. name
    2. text
    3. profile_image_url
       
  4. when XML fully parsed, the text of the two elements and image of the third is displayed

The XML includes the following interesting elements:

<name>Ray Garraud</name>
<profile_image_url>http://a1.twimg.com/profile_images/636002114/rayray_normal.jpg</profile_image_url>
<text>Sudden gust of wind / footsteps on the promenade / a little faster / © / #Haiku #FB</text> 

which, when a callback is received from the parser, are added to a dictionary as:

Key Value
name Ray Garraud
text Sudden gust of wind / footsteps on the promenade / a little faster / © / #Haiku #FB
profile_image_url http://a1.twimg.com/profile_images/636002114/rayray_normal.jpg

Dictionary, currentTweetDict, entries are added by:

[currentTweetDict setValue: @"Ray Garraud" forKey: @"name"];

name and text values are copied to a UITextBox for display.

profile_image_url value is the URL of the image displayed in a UIWebView object by:

NSURL *url = [NSURL URLWithString: [currentTweetDict valueForKey:@"profile_image_url"] ];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
[tweetWebView loadRequest: request];   
#import "SimpleTwitterClientViewController.h"

#define INTERESTING_TAG_NAMES @"text", @"name", @"profile_image_url", nil

@implementation SimpleTwitterClientViewController

@synthesize tweetsView, activityIndicator, tweetUserTextField, tweetWebView;

- (void) viewDidLoad {
	[super viewDidLoad];
	interestingTags = [[NSSet alloc] initWithObjects: INTERESTING_TAG_NAMES];
}

-(IBAction) updateTweets {
	tweetsView.text = @"";
	if(tweetsData) [tweetsData release];
	tweetsData = [[NSMutableData alloc] init];

	NSString *urlString = [[NSString alloc] initWithFormat: 
                                         		@"http://twitter.com/users/show.xml?screen_name=%@", 
                                          		tweetUserTextField.text];
	NSURL *url = [NSURL URLWithString: urlString ];
	NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
	NSURLConnection *connection = [[NSURLConnection alloc]
			   initWithRequest:request
			   	   delegate:self];
	[connection release];
	[request release];
	[urlString release];

	[activityIndicator startAnimating];
}

- (void) startParsingTweets {
	NSXMLParser *tweetParser = [[NSXMLParser alloc] initWithData: tweetsData];

	tweetParser.delegate = self;
	[tweetParser parse];
	[tweetParser release];
}
#pragma mark NSURLConnection callbacks

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
	[tweetsData appendData: data];
}

- (void) connectionDidFinishLoading: (NSURLConnection*) connection {
	[activityIndicator stopAnimating];
	[self startParsingTweets];
}
-(void) connection:(NSURLConnection *)connection
  didFailWithError: (NSError *)error {
	UIAlertView *errorAlert = [[UIAlertView alloc]
				   initWithTitle: [error localizedDescription]
				   message: [error localizedFailureReason]
				   delegate:nil
				   cancelButtonTitle:@"OK"
				   otherButtonTitles:nil];
	[errorAlert show];
	[errorAlert release];
	[activityIndicator stopAnimating];
}

- (void)parserDidStartDocument:(NSXMLParser *)parser {
	[tweetsString release];
	tweetsString = [[NSMutableString alloc] init];
	currentElementName = nil;
	currentText = nil;
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *) elementName
		namespaceURI:(NSString *)namespaceURI
		qualifiedName:(NSString *)qualifiedName
		attributes:(NSDictionary *)attributeDict {

	if ([elementName isEqualToString:@"user"]) {			// Reset for this Twitter user
		[currentTweetDict release];
		currentTweetDict = [[NSMutableDictionary alloc] initWithCapacity: [interestingTags count]];
	}
	else if ([interestingTags containsObject: elementName]) {
		currentElementName = elementName;
		currentText = [[NSMutableString alloc] init];
	}
 }
// <name>Ray Garraud</name>
// <profile_image_url>http://a1.twimg.com/rayray_normal.jpg</profile_image_url>
// <text>Sudden gust of wind / footsteps on the promenade</text>
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
		namespaceURI:(NSString *)namespaceURI
		qualifiedName:(NSString *)qName {
										// Found ending element tag
	if ([elementName isEqualToString:currentElementName]) {
		[currentTweetDict setValue: currentText forKey: currentElementName];
	} 
           else if ([elementName isEqualToString:@"user"]) {		// End of this user info

		[tweetsString appendFormat:@"Name: %@\nLast Tweet: %@\n",
			[currentTweetDict valueForKey:@"name"],
			[currentTweetDict valueForKey:@"text"]
		];
		NSURL *url = [NSURL URLWithString: 
                                                   [currentTweetDict valueForKey:@"profile_image_url"] ];
		NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];

		[tweetWebView loadRequest: request];      		// Display image

		[request release];
	}
	[currentText release];
	currentText = nil;
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
	[currentText appendString:string];
}

- (void)parserDidEndDocument:(NSXMLParser *)parser {
	tweetsView.text = tweetsString;
           [tweetsString release];
	[activityIndicator stopAnimating];
}
- (BOOL)textFieldShouldReturn: (UITextField *)textField {
	[textField resignFirstResponder];
	return YES;
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; 
}
- (void)dealloc {
    [tweetsView release];
    [activityIndicator release];
    [interestingTags release];
    [tweetsData release];
    [super dealloc];
}
@end
#import <UIKit/UIKit.h>

@interface SimpleTwitterClientViewController : UIViewController {
	UITextView 			*tweetsView;
	UITextField 			*tweetUserTextField;
	UIActivityIndicatorView 	*activityIndicator;
	UIWebView 			*tweetWebView;

	NSMutableData 		*tweetsData;

	NSMutableString 		*tweetsString;
	NSMutableDictionary 	*currentTweetDict;
	NSString 			*currentElementName;
	NSMutableString 		*currentText;

	NSSet 				*interestingTags;
}

@property (nonatomic, retain) IBOutlet UITextField *tweetUserTextField;
@property (nonatomic, retain) IBOutlet UITextView *tweetsView;
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activityIndicator;
@property (nonatomic, retain) IBOutlet UIWebView *tweetWebView;

-(IBAction) updateTweets;

@end