How the heck do you connect to a JSON API that is remote (in iOS)?
Using curl, its easy. Using iOS, there's a few more steps. First we need to put our data into some sort of dictionary (well, at least that's what I wanted to do). Inside the viewDidLoad method, you can just use NSMutableDictionary. This data will need to be serialized afterwards in order to prep it to be sent to the API.
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithDictionary:@{ @"op" : @"login", @"user" : login, @"password" : password }]; [self fetchData:dictionary]; [self getCategories:_sid];Then we need to serialize the data. The magic is done in the fetchData method. Actually, all the heavy lifting is done the the fetchData method, let's break it down a little.
- (void)fetchData:(NSMutableDictionary *)dictionary { NSError *error = nil; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:&error]; if ([jsonData length] > 0 && error == nil){ NSLog(@"Successfully serialized the dictionary into data."); NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSLog(@"JSON String = %@", jsonString);Now that we have a serialized object, we can now get it ready to be sent.
// create the connection and send it to the server NSString *requestString = kTinyTinyRSSURL; NSURL *url = [NSURL URLWithString:requestString]; NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; [req setHTTPMethod:@"POST"]; NSString *dataString = jsonString; NSData *requestData = [NSData dataWithBytes:[dataString UTF8String] length:[dataString length]]; [req setHTTPBody:requestData]; NSURLResponse *theResponse = NULL; NSError *theError = NULL; NSData *theResponseData = [NSURLConnection sendSynchronousRequest:req returningResponse:&theResponse error:&theError];
The money here is theResponseData, it allows you to POST the data to the server. Once you have sent the data, you will get back a response, so you need to deserialize that back into something useful. I'm putting it into a NSArray.
//deserialize the response into something usable NSDictionary* json = [NSJSONSerialization JSONObjectWithData:theResponseData //1 options:kNilOptions error:&error]; NSArray* validResponse = [json objectForKey:@"content"]; //2 NSLog(@"content: %@", validResponse); //3
That's basically it. fetchData is reusable, so you can now use the same method to make other JSON queries. As per the gist, anyone should be able to use the code to connect to a JSON API.
Note: I mashed together a lot of this code from:
- the iOS Cookbook (for serializing/deserializing objects)
- StackOverflow - "Objective C equivalent of cURL to work with JSON"
- Working with JSON in iOS 5 (an excellent resource). It gave good insights, but did not deal with trying parse the data or use it in a nice way (i.e.: the session ID/sid).
- My full code snip can be found here: https://gist.github.com/kgdesouz/5542543/.
- The code was meant to be quick and dirty. I didn't really follow the MVC, since really I didn't need the view or the controller, just the model. I wanted everything to go to stdout (to keep things simple). I basically just looked at some tutorials and tried to integrate it.
- There's no GUI component required. Without too much effort, anyone should be able to use the code for any JSON calls, with a little tweaking.
- There is a lot of clean up required. I'm still playing with unit testing in this language. Specifically, JSON unit testing. Its a little different since I need to figure out how to reset the JSON. I will probably create a JSON mock object to do this.
- I totally didn't use getter and setter methods here. I know I should, but read the first bullet point; quick and dirty.