RestKit is a framework that aims to simplify the "plumbing" of your application to allow you to focus on your core features. In this screencast, I focus on fetching JSON from an API and mapping it onto our own objects using RestKit's mapping features.
Episode Links Episode source code RestKit homepage RestKit at Github RestKit API Reference RestKit Mapping The API For the API in this episode, I used BreweryDB, who was gracious enough to let you use a temporary API key for the sample app. It should last at least for the next few weeks to make it easier for you to follow along. If the API key doesn't work for you you'll get an error, in which case you can sign up for your own key (which is free). The API documentation can be found here: http://www.brewerydb.com/developers/docs. The models We are only interested in a subset of the information provided by the API. For this information, we create 3 classes to represent the structure we're after: BeerStyle, Beer, and Brewery. @interface BeerStyle : NSObject @property (nonatomic, assign) NSInteger styleId; @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *styleDescription; @property (nonatomic, copy) NSString *category; @end @interface Beer : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *ibu; @property (nonatomic, copy) NSString *abv; @property (nonatomic, copy) NSString *labelIconImageUrl; @property (nonatomic, strong) NSArray *breweries; @property (nonatomic, readonly) NSString *brewery; @end @interface Brewery : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *website; @end The mappings Next we simply tell RestKit how to map the JSON structure onto these objects. @implementation MappingProvider + (RKMapping *)beerStyleMapping { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[BeerStyle class]]; [mapping addAttributeMappingsFromArray:@[@"name"]]; [mapping addAttributeMappingsFromDictionary:@{ @"id": @"styleId", @"description": @"styleDescription", @"category.name": @"category" }]; return mapping; } + (RKMapping *)beerMapping { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Beer class]]; [mapping addAttributeMappingsFromArray:@[@"name", @"ibu", @"abv"]]; [mapping addAttributeMappingsFromDictionary:@{@"labels.icon": @"labelIconImageUrl"}]; [mapping addRelationshipMappingWithSourceKeyPath:@"breweries" mapping:[MappingProvider breweryMapping]]; return mapping; } + (RKMapping *)breweryMapping { RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Brewery class]]; [mapping addAttributeMappingsFromArray:@[@"name", @"website"]]; return mapping; } Note the difference between adding attributes from the array (for the cases where our property matches the attribute in the JSON document. For the ones that differ, we can map that with a dictionary, where the left side key is the JSON attribute and the value is our model's property. We can also flatten out structures, as you see for category.name mapping to category on BeerStyle. Finally, to represent nested child objects, we add a relationship mapping. RestKit automatically converts a JSON array to an object array using the mapping provided, so here we'll end up with an array of Brewery objects. Fetching data using the mappings NSIndexSet *statusCodeSet = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); RKMapping *mapping = [MappingProvider beerStyleMapping]; RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:@"/v2/styles" keyPath:@"data" statusCodes:statusCodeSet]; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://api.brewerydb.com/v2/styles?key=%@", BREWERY_DB_API_KEY ]]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; [operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { self.styles = mappingResult.array; [self.tableView reloadData]; } failure:^(RKObjectRequestOperation *operation, NSError *error) { NSLog(@"ERROR: %@", error); NSLog(@"Response: %@", operation.HTTPRequestOperation.responseString); }]; [operation start];