Consuming RESTful API with RESTframework

As explained in previous post, we’re going to demonstrate how RESTframework handles REST web services. I’ll be consuming a simple Django demo web service created in previous post, so either grab the sources or read the post and build it yourself. Assuming you have this service running on localhost, port 8000, we can continue.

First, download RESTframework from GitHub. With git client, simply type in terminal:

$ git clone git@github.com:ivasic/RESTframework.git

The quickest way to get RESTframework into your project is just including all the files from RFClasses  folder. RF does not have any external dependencies so building shouldn’t be a problem.

RFClasses

RFClasses

Now, we’ll also need JSONKit to parse API response and MBProgressHUD to show some progress. Grab both from GitHub and add to your project.

Fetching objects list

We’ll have 2 view controllers in our demo app. One will be a simple object list and the other one will be, even more simple, view controller for creating a new object. First, we’re going to show how to fetch the object list. We’ll need a GET request to /objects/ URL and we’ll need to parse the JSON array we get in response and show in the table view.

RFRequest* r = [RFRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8000/"] type:RFRequestMethodGet resourcePathComponents:@"objects", nil];
[MBProgressHUD showHUDAddedTo:self.view animated:YES].labelText = NSLocalizedString(@"Loading...", @"");
[RFService execRequest:r completion:^(RFResponse* response) {
	[MBProgressHUD hideHUDForView:self.view animated:YES];
 
	if (response.error) {
		UIAlertView* aiv = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", @"") message:response.error.localizedDescription delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];
		[aiv show];
		return;
	}
 
	self.dataSource = [response.dataValue objectFromJSONData];
	[self.tableView reloadData];
}];

So, what we’re doing in this code snippet is:

  • Creating a GET RFRequest with appropriate URL and resource path
  • Attaching MBProgressHUD to our view to show spinner progress
  • Executing RFRequest and defining the block to execute after RFResponse is received
  • Inside this block, we simply check for errors, parse the response, add to our tableView dataSource and reloading the table
You can see all this in action in the project sample attached to this blog post (at the bottom).

Creating new objects

Our view controller for creating new objects is responsible for creating POST requests to /objects/ URL. Again, very simple, you just need to do this:

RFRequest* r = [RFRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8000/"] type:RFRequestMethodPost resourcePathComponents:@"objects", @"", nil];
 
[r addParam:self.txtName.text forKey:@"name"];
[r addParam:self.lblDate.text forKey:@"date"];
 
[MBProgressHUD showHUDAddedTo:self.view animated:YES].labelText = NSLocalizedString(@"Submitting...", @"");
[RFService execRequest:r completion:^(RFResponse* response) {
	[MBProgressHUD hideHUDForView:self.view animated:YES];
 
	if (response.error) {
		UIAlertView* aiv = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", @"") message:response.error.localizedDescription delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];
		[aiv show];
		return;
	}
 
	UIAlertView* aiv = [[[UIAlertView alloc] initWithTitle:@"Success" message:@"Success" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];
	[aiv show];
 
	[self.navigationController popViewControllerAnimated:YES];
}];

Similar to our previous snippet, but this time we also add some parameters to the request – name and date strings.

This is a brief overview with sample Xcode project of how RESTframework consumes RESTful web APIs. Questions welcomed via comments as usual.

 

Download project: RESTframework demo Xcode project download

REST framework for iOS is now Open Source

I have (finally) open sourced my RESTframework project on GitHub. It aims for simplicity of usage primarily. Querying RESTful web services is really easy now. Supported are iOS versions 4.0 and above and Mac OS 10.6 and above.

Feel free to fork & contribute!

RESTframework on GitHub

Some XCode 4 tips

Apple kind of surprised me with releasing the XCode 4 along with the iOS 4.3. Honestly, I wasn’t expecting it until later this year or at least until iOS 5 was announced. But I’m glad it’s out, of course, and I already switched to using it vs XCode 3. I held back from trying out the beta versions so the experience was really exciting to me when I first tried it. Completely different experience compared to version 3.x and finally a single, fullscreen window. Pretty cool.

Anyway, I’m not going to review it as there are lots of reviews, I’m just going to point out a few things that I ran into while testing the last few days.

How to enable LLVM in XCode 4

By default, XCode uses a GCC kind of wrapper for LLVM so you’ll probably want to enable LLVM compiler and you can do that easily enough in build settings like so.

Now that you enabled that naturally you want to enable LLDB too. LLDB is a debugger, it’s to LLVM what GDB is to GCC. To enable LLDB you need to choose “Edit Scheme” from the “Product” menu and for the “Run” phase you’ll see a debugger chooser dropdown. However, at this point for iOS projects you’re stuck with GDB as the LLDB is only available for Mac apps and not available for iOS, yet.

How do I add existing frameworks to the XCode 4 projects?

“Add the existing framework…” right click menu option is gone. So how do you add existing frameworks?! The option is there of course, it’s just a bit hidden. The trick is to open target settings and navigate to the “Build Phases” tab. There’s a section that says “Link binary with Libraries” and that’s our X. See below.

Add existing frameworks

Add existing frameworks

So, should I switch to XCode 4?

Yup. I was in doubt and thought it might be a good idea to hold off of it for a while, at least until the next version but I tried it and found nothing that stops me from using it. In fact, I’m so pleased I’m having a hard time coding some legacy projects in XCode 3. I would suggest, though, to keep the version 3.x and install XCode 4 in a separate directory just in case…

UPDATE:

Where do I set NSZombieEnabled?

Got another tip here, it’s moved to a different place now. You need to choose “Edit Scheme” from the “Product” menu and you’ll find it there.

Edit Scheme Xcode 4

Edit Scheme Xcode 4

6 Useful Objective C & Cocoa macros

Here are a few useful cocoa & cocoa touch macros that I’ve come across and thought I share here. Some of those I use regularly and some I just know about but you may find them useful.

Hex (HTML) color to UIColor macro

I found this macro a long time ago somewhere and I’m not sure what’s the original source, yet the Google search returned this blog so I’m going to give him the credit.

#define HEXCOLOR(c) [UIColor colorWithRed:((c>>24)&0xFF)/255.0
                                  green:((c>>16)&0xFF)/255.0
                                     blue:((c>>8)&0xFF)/255.0 \
                                    alpha:((c)&0xFF)/255.0]
//usage
UIColor* color = HEXCOLOR(0xff00ff00);

Enumerating collections macros

The following macro helps you with fast enumeration over collections, credit goes to Wincent.

#define WOEnumerate(collection, object)                                     \
for (id enumerator = [collection objectEnumerator],                         \
     selector = (id)@selector(nextObject),                                  \
     method = (id)[enumerator methodForSelector:(SEL)selector],             \
     object = enumerator ? ((IMP)method)(enumerator, (SEL)selector) : nil;  \
     object != nil;                                                         \
     object = ((IMP)method)(enumerator, (SEL)selector))
 
#define WOKeyEnumerate(collection, object)                                  \
for (id enumerator = [collection keyEnumerator],                            \
     selector = (id)@selector(nextObject),                                  \
     method = (id)[enumerator methodForSelector:(SEL)selector],             \
     object = enumerator ? ((IMP)method)(enumerator, (SEL)selector) : nil;  \
     object != nil;                                                         \
     object = ((IMP)method)(enumerator, (SEL)selector))

Logging macros

CMLog - use to extend NSLog functionality.

#define CMLog(format, ...) NSLog(@"%s:%@", __PRETTY_FUNCTION__,[NSString stringWithFormat:format, ## __VA_ARGS__]);
 
//usage
CMLog(@"My iPhone is an %@, v %@", [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion]);

MARK - method stamp macro, use to output class and method name.

#define MARK	CMLog(@"%s", __PRETTY_FUNCTION__);

Benchmarking macros

Use START_TIMER and END_TIMER to get the timing between these two calls.

#define START_TIMER NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
#define END_TIMER(msg) 	NSTimeInterval stop = [NSDate timeIntervalSinceReferenceDate]; CMLog([NSString stringWithFormat:@"%@ Time = %f", msg, stop-start]);
 
//usage example
- (NSData *)loadDataFromURL:(NSString *)dataURL
{
  START_TIMER;
  NSData *data = [self doSomeStuff:dataURL];
  END_TIMER(@"loadDataFromURL");
  return data;
}

Logging and benchmarking macros, courtesy of Stephan Burlot.

UIView frame (CGRect) macros

And for the end, here’s my own modest addition to the list. When developing an iPhone or iPad apps, you probably found yourself lots of times working with UIView frames, changing them etc… Often times I just change the UIView size or I just need to move it around the screen, reposition the view and each time I need to do CGRectMake etc… The following macros have helped me and saved me some typing.

#define width(a) a.frame.size.width
#define height(a) a.frame.size.height
#define top(a) a.frame.origin.y
#define left(a) a.frame.origin.x
#define FrameReposition(a,x,y) a.frame = CGRectMake(x, y, width(a), height(a))
#define FrameResize(a,w,h) a.frame = CGRectMake(left(a), top(a), w, h)

Obviously you can do the same for UIView ‘bounds’ instead of ‘frame’.

Fetching emails from Gmail using Cocoa

I built this contact form for one website (my company’s) and at the time it was least expensive to just shoot out emails to a specific address with user’s messages and email addresses. Naturally, at one point I had to collect those emails & messages and use them so I ran into problem – what’s the easiest way to do that? Fortunately, our email server was GMail so I found a couple of ways to do it, avoid writing IMAP client and the easiest way for me was to use GMail’s built-in RSS feed and simply parse this feed to get what I want. In Cocoa, this should be simple enough but turned out not to be in my case.

Cocoa’s PubSub framework offers a nice way of subscribing to RSS feeds and it was ideal and simple for usage in this particular case. However, I just couldn’t get it to work with GMail’s authentication. I’ll explain below.

First I had to set up GMail account for easier access to the emails. Using search & filters, I found all emails that contained the info I needed and moved them to a separate temporary GMail label I created. At the same time I marked all emails as unread. This is very important because only unread emails appear in RSS feed and without this step, the feed for the label would appear empty.

Now the coding part. Ideally we would simply get PSClient and create a PSFeed, set username and password and traverse PSEntry objects in the feed. In theory, we’d do this:

PSClient *client = [PSClient applicationClient];
	NSURL    *url    = [NSURL URLWithString:@"https://mail.google.com/a/feed/atom/LABELNAME"];
	PSFeed   *feed   = [client feedWithURL:url];
 
	feed.login = txtEmail.stringValue;
	[feed setPassword:txtPass.stringValue];
 
	NSLog(@"Err: %@", feed.lastError);
 
	// Retrieve the entries as an unsorted enumerator
	NSEnumerator *entries = [feed entryEnumeratorSortedBy: nil];
	PSEntry *entry;
 
	// Go through each entry and get what we need
	while (entry = [entries nextObject]) {
		NSLog(@"%@", entry.summary.plainTextString);
	}

And this should work. However, it doesn’t. I always get this:

Err: Error Domain=NSURLErrorDomain Code=-1013 UserInfo=0x10017e450 "A username and password are required"

I still haven’t found the solution for this using PubSub framework. However I did manage to get the feed using plain HTTP NSConnection and simple authentication. So if anyone knows why this happens and/or knows how to solve it I would really appreciate if you notified me, thanks.

Anyway, back to our problem. Since this didn’t work, I simply tweaked it a bit and did a few things manually. I decided to use PSFeed’s initWithData:url: and pass the data (XML) manually from a NSTextField. First I opened the feed URL in my browser and logged in so I could actually see the feed. Then I opened the XML source of the feed and copied it to clipboard. Modified my GUI and added one more NSTextField which I used to paste XML feed data in and modified the Objective-C  Cocoa code like this:

	PSClient *client = [PSClient applicationClient];
	NSURL    *url    = [NSURL URLWithString:@"https://mail.google.com/mail/feed/atom/LABELNAME"];
	PSFeed   *feed   = [[[PSFeed alloc] initWithData:[txtInput.stringValue dataUsingEncoding:NSUTF8StringEncoding] URL:url] autorelease];
 
	feed.login = txtEmail.stringValue;
	[feed setPassword:txtPass.stringValue];
 
	NSLog(@"Err: %@", feed.lastError);
 
	// Retrieve the entries as an unsorted enumerator
	NSEnumerator *entries = [feed entryEnumeratorSortedBy: nil];
	PSEntry *entry;
 
	// Go through each entry and get what we need
	while (entry = [entries nextObject]) {
		NSLog(@"%@", entry.summary.plainTextString);
	}

And it finally worked fine. I parsed the feed manually and yeah, this isn’t exactly automated example but I did what I needed to do. And again, if anyone knows the solution to the authentication problem I’d love to hear it.

Consuming ASP.NET web services in iOS part 2

In previous blog post I’ve explained how to create iOS friendly ASP .NET web service with JSON RPC so now we’re going to take it further by creating an iPhone app that will consume this web service. Since iOS natively does not support JSON, we’ll be using this nice JSON framework available on Google Code here. This framework provides NSObject categories which allow simple JSON parsing and and it’s really convenient to use with iOS SDK. Other than that, we’ll be using native iOS SDK APIs only to create HTTP connection and query our JSON RPC service. Calling this web service is done by creating NSURLRequest with HTTP POST method and passing method name, method parameters (arguments) and identificator. NSURLConnection uses this request and does the magic we need. Let’s see the code.

First, we need to create JSON string which we’re going to POST to our RPC service. We do this by simply creating a dictionary and breaking it down to JSON representation.

 
//RPC
 
NSMutableDictionary* reqDict = [NSMutableDictionary dictionary];
 
[reqDict setObject:methodName forKey:@"method"];
 
[reqDict setObject:parameters forKey:@"params"];
 
[reqDict setObject:identificator forKey:@"id"];
 
//RPC JSON
 
NSString* reqString = [NSString stringWithString:[reqDict JSONRepresentation]];

We should note 3 arguments we’re posting to the service – method, params and id. Method is RPC method name as declared in JSON RPC web service. Params are arguments this method requires and ‘id’ is the call identifier which RPC call returns when sending back response and it’s used to link the response to the request in case you’re sending out multiple requests. In our case, the method name is ‘HelloWorld’ without arguments and as the identifier we’ll just put 1.

So now we create NSURLRequest and NSURLConnection using this reqString. This is the main part of code so pay attention.

 
//Request
 
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
 
NSData* requestData = [NSData dataWithBytes:[reqString UTF8String] length:[reqString length]];
 
//prepare http body
 
[request setHTTPMethod: @"POST"];
 
[request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];
 
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
 
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
 
[request setHTTPBody: requestData];

First we create a mutable url request, set it’s HTTP method to “POST” and fill out other HTTP specific header fields. Finally we set our JSON request string as HTTP body.

Now we simply create NSURLConnection, assign a delegate to it and wait for our data.

 
urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
 
[request release];

The delegate part of the calling object has these methods defined.

#pragma mark -
#pragma mark NSURLConnection delegate
 
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
	NSLog(@"Did receive response: %@", response);
 
	[webData release];
	webData = [[NSMutableData alloc] init];
}
 
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
	assert(webData != nil);
	[webData appendData:data];
}
 
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
	[webData release];
	webData = nil;
	[urlConnection release];
	urlConnection = nil;
 
	UIApplication* app = [UIApplication sharedApplication];
	app.networkActivityIndicatorVisible = NO;
 
	//notify
	[delegate loadingFailed:[error localizedDescription]];
}
 
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
	[urlConnection release];
	urlConnection = nil;
 
	UIApplication* app = [UIApplication sharedApplication];
	app.networkActivityIndicatorVisible = NO;
 
	//DO something with webData
	[delegate dataLoaded:webData];
 
	[webData release];
	webData = nil;
}

Once the connection gets a response we create NSData (webData) and we append bytes to it in didReceiveData callback. In the end we either get didFailWithError or didFinishLoading and take actions accordingly.

Finally, the app would return something like this when launched.

iPhone calling JSON RPC web service

iPhone JSON RPC

For your convenience, I have attached XCode project for download. Please note that this is an example only and should be treated as such, I don’t provide guarantee of any kind for this code.

JSON RPC iOS example project