two toasters - presentation - restkit for rubyists

27
RestKit for Rubyists Blake Watters Wednesday, March 16, 2011

Upload: dordoka-maisu

Post on 22-Oct-2014

234 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Two Toasters - Presentation - RestKit for Rubyists

RestKit for RubyistsBlake Watters

Wednesday, March 16, 2011

Page 2: Two Toasters - Presentation - RestKit for Rubyists

2

What is RestKit?

Wednesday, March 16, 2011

Page 3: Two Toasters - Presentation - RestKit for Rubyists

RestKit is a RESTful Object Mapping Framework for Cocoa

// Read the Twitter Timeline in 10 lines of code- (void)loadTwitterTimeline { RKObjectManager* objectManager = [RKObjectManager sharedManager]; NSString* timelinePath = @"/status/user_timeline/RestKit.json"; [objectManager loadObjectsAtResourcePath:timelinePath objectClass:[Tweet class] delegate:self];}

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects { NSLog(@"Loaded Tweets: %@", objects);}

- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error { NSLog(@"Encountered an Error Loading Tweets: %@", error);}

3

Wednesday, March 16, 2011

Page 4: Two Toasters - Presentation - RestKit for Rubyists

4

RestKit Architecture

• Network Layer

• Object Mapping

• Core Data

• Integration Points

Wednesday, March 16, 2011

Page 5: Two Toasters - Presentation - RestKit for Rubyists

Network Layer

5

Wednesday, March 16, 2011

Page 6: Two Toasters - Presentation - RestKit for Rubyists

6

Key Concepts

• RKClient - Your user agent

• Base URLs and Resource Paths

• RKRequest & RKResponse - The HTTP lifecycle

• RKParams - Multi-part MIME requests

• Reachability - Detecting offline/online status

Wednesday, March 16, 2011

Page 7: Two Toasters - Presentation - RestKit for Rubyists

Initializing RKClient

- (void)initRKClient {! // Initialize with a Base URL! RKClient* client = [RKClient clientWithBaseURL:@"http://restkit.org"];!! // Setup HTTP AUTH! client.username = @"restkit";! client.password = @"rocks";!! // Set an app-wide API key HTTP header! [client setValue:@"123456" forHTTPHeaderField:@"X-RESTKIT-API-KEY"];!! // The first initialized RKClient becomes! // the sharedClient instance! [[RKClient sharedClient] isNetworkAvailable];}

7

Wednesday, March 16, 2011

Page 8: Two Toasters - Presentation - RestKit for Rubyists

Sending Requests

- (void)sendRequest {! // Send an HTTP GET request to 'http://restkit.org/contacts'! [[RKClient sharedClient] get:@"/contacts" delegate:self];}

// RKRequestDelegate methods

- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response {! NSLog(@"Yay! We Got a response");}

- (void)request:(RKRequest*)request didFailLoadWithError:(NSError*)error {! NSLog(@"Oh no! We encountered an error: %@", [error localizedDescription]);}

8

Wednesday, March 16, 2011

Page 9: Two Toasters - Presentation - RestKit for Rubyists

Processing Responses

- (void)sendRequest {! // Send an HTTP GET request to 'http://restkit.org/contacts'! [[RKClient sharedClient] get:@"/contacts" delegate:self];}

- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response {! NSLog(@"Request Headers: %@", [response allHeaderFields]);! NSLog(@"Cookies: %@", [response cookies])!! if ([response isSuccessful]) {! ! // Response status was 200..299! ! if ([response isCreated] && [response isJSON]) {! ! ! // Looks like we have a 201 response of type 'application/json'! ! ! NSLog(@"The JSON is %@", [response bodyAsJSON]);! ! }! } else if ([response isError]) {! ! // Response status was either 400..499 or 500..599! ! NSLog(@"Ouch! We have an HTTP error. Status Code description: %@", [response localizedStatusCodeString]);! }}

9

Wednesday, March 16, 2011

Page 10: Two Toasters - Presentation - RestKit for Rubyists

Requests with Parameters

- (void)sendRequestWithParams {! // Simple params! NSDictionary* paramsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:! ! ! ! ! ! ! ! ! @"Joe Blow", @"name",! ! ! ! ! ! ! ! ! @"Two Toasters", @"company", nil];! [[RKClient sharedClient] post:@"/contacts" params:paramsDictionary delegate:self];!! // Multi-part params via RKParams!! RKParams* params = [RKParams paramsWithDictionary:paramsDictionary];! NSData* imageData = UIImagePNGRepresentation([UIImage imageNamed:@"picture.jpg"]);! [params setData:imageData MIMEType:@"image/png" forParam:@"photo"];! [params setFile:@"bio.txt" forParam:@"attachment"];! [[RKClient sharedClient] post:@"/contacts" params:params delegate:self];}

10

Wednesday, March 16, 2011

Page 11: Two Toasters - Presentation - RestKit for Rubyists

Reachability

- (void)demoReachability {! // Check if the network is available! [[RKClient sharedClient] isNetworkAvailable];!! // Register for changes in network availability! NSNotificationCenter* center = [NSNotificationCenter defaultCenter];! [center addObserver:self selector:@selector(reachabilityDidChange:) name:RKReachabilityStateChangedNotification object:nil];}

- (void)reachabilityDidChange:(NSNotification*)notification {! RKReachabilityObserver* observer = (RKReachabilityObserver*) [notification object];! RKReachabilityNetworkStatus status = [observer networkStatus];! if (RKReachabilityNotReachable == status) {! ! NSLog(@"No network access!");! } else if (RKReachabilityReachableViaWiFi == status) {! ! NSLog(@"Online via WiFi!");! } else if (RKReachabilityReachableViaWWAN == status) {! ! NSLog(@"Online via Edge or 3G!");! }} 11

Wednesday, March 16, 2011

Page 12: Two Toasters - Presentation - RestKit for Rubyists

Object Mapping

12

Wednesday, March 16, 2011

Page 13: Two Toasters - Presentation - RestKit for Rubyists

@interface Contact

Modeling a RESTful Service

13

/contacts[{        'contact':  {                'id':  1234,                'name':  'Blake  Wa8ers',                'email':  '[email protected]',                'company':  'Two  Toasters'        }},{        'contact':  {                'id':  3456,                'name':  'Rachit  Shukla',                'email':  '[email protected]',                'company':  'Two  Toasters'        }}]

@interface  Contact  :  RKObject  {    NSNumber*  _contactID;    NSString*  _name;    NSString*  _email;    NSString*  _company}

   @property  (retain)  NSNumber*  contactID;    @property  (retain)  NSString*  name;    @property  (retain)  NSString*  email;    @property  (retain)  NSString*  company;@end

Wednesday, March 16, 2011

Page 14: Two Toasters - Presentation - RestKit for Rubyists

Initializing the Object Manager

- (void)initObjectManager {! RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:@"http://restkit.org"];!! // Object manager has a client! [objectManager.client setValue:@"123456" forHTTPHeaderField:@"X-RESTKIT-API-KEY"];!! // Shared manager instance also! // Register JSON element <-> class mappings! [[RKObjectManager sharedManager] registerClass:[Contact class] forElementNamed:@"contact"];}

14

Wednesday, March 16, 2011

Page 15: Two Toasters - Presentation - RestKit for Rubyists

Mapping Elements to Properties

// RKObjectMappable delegate method// Instructs RestKit how to map items in the payload <-> object properties+ (NSDictionary*)elementToPropertyMappings {! return [NSDictionary dictionaryWithKeysAndObjects:! ! ! @"name", @"name",! ! ! @"contact_id", @"contactID",! ! ! @"email", @"email",! ! ! nil];}

15

Wednesday, March 16, 2011

Page 16: Two Toasters - Presentation - RestKit for Rubyists

Loading Remote Objects

- (void)loadRemoteObjects {! [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/contacts" delegate:self];}

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray *)objects {! if ([objectLoader wasSentToResourcePath:@"/contacts"]) {! ! // Introspect the resource path! ! NSLog(@"Nice! We loaded the following contacts: %@", objects);! }}

- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error {! // Note that failures here can be at the _application_ level in addition to transport! NSLog(@"Rats! Failed to load objects: %@", [error localizedDescription]);}

16

Wednesday, March 16, 2011

Page 17: Two Toasters - Presentation - RestKit for Rubyists

17

What just happened?

• RKObjectManager configured to map ‘contact’ dictionaries to Contact class

• Asynchronous GET sent to ‘/contacts’ via RKObjectLoader

• 200 response returned, with JSON body

• RKObjectMapper parsed payload and mapped JSON data to Contact objects

• Callback invoked with array of Contacts

Wednesday, March 16, 2011

Page 18: Two Toasters - Presentation - RestKit for Rubyists

Configuring the Router

- (void)configureRouter {! RKDynamicRouter* router = [RKDynamicRouter new];!! // Configure a default route! [router routeClass:[Contact class] toResourcePath:@"/contacts/(contactID)"];! [router routeClass:[Contact class] toResourcePath:@"/contacts" forMethod:RKRequestMethodPOST];! [RKObjectManager sharedManager].router = router;}

18

Wednesday, March 16, 2011

Page 19: Two Toasters - Presentation - RestKit for Rubyists

RESTful Object Manipulation

// Create a new Contact- (void)createObject {! Contact* contact = [Contact new];! contact.name = @"RestKit User";! contact.email = @"[email protected]";!! // POST to /contacts! [[RKObjectManager sharedManager] postObject:contact delegate:self];}

// Edit Contact with ID 12345- (void)editObject {! Contact* contact = [Contact new];! contact.contactID = [NSNumber numberWithInt:12345];! contact.name = @"New Name";!! // POST to /contacts/12345! [[RKObjectManager sharedManager] putObject:contact delegate:self];}

// Delete Contact with ID 321- (void)deleteObject {! Contact* contact = [Contact new];! contact.contactID = [NSNumber numberWithInt:321];!! // DELETE to /contacts/321! [[RKObjectManager sharedManager] deleteObject:contact delegate:self];!} 19

Wednesday, March 16, 2011

Page 20: Two Toasters - Presentation - RestKit for Rubyists

Core Data

20

Wednesday, March 16, 2011

Page 21: Two Toasters - Presentation - RestKit for Rubyists

Configuring RKManagedObjectStore

- (void)configureObjectStore { // Initialize the RestKit Object Manager RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:@"http://restkit.org"];! // Initialize object store // We are using the Core Data support, so we have initialized a managed object store backed // with a SQLite database. objectManager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"Contacts.sqlite"];}

21

Wednesday, March 16, 2011

Page 22: Two Toasters - Presentation - RestKit for Rubyists

Making Contact Persistent

#import <RestKit/CoreData/CoreData.h>

@interface Contact : RKManagedObject {}

@end

@implementation Contact

@dynamic name;@dynamic email;@dynamic company;@dynamic contactID;

// Define our property mappings+ (NSDictionary*)elementToPropertyMappings {! return [NSDictionary dictionaryWithKeysAndObjects:! ! ! @"name", @"name",! ! ! @"email", @"email",! ! ! @"company", @"company",! ! ! @"contact_id", @"contactID"! ! ! nil];}

// Tell RestKit which property contains the primary key+ (NSString*)primaryKeyProperty {! return @"contactID";}

@end 22

Wednesday, March 16, 2011

Page 23: Two Toasters - Presentation - RestKit for Rubyists

Working with Core Data

- (void)workWithCoreData {! // Get all the Contacts! NSArray* contacts = [Contact allObjects];!! // Count the Contacts! NSError* error = nil;! NSUInteger count = [Contact count:&error];!! // Find Contact by primary key! NSNumber* contactID = [NSNumber numberWithInt:12345];! Contact* somebody = [Contact objectWithPrimaryKeyValue:contactID];!! // Find Contacts with criteria! NSPredicate* predicate = [NSPredicate predicateWithFormat:@"name contains[cd] 'restkit'"];! NSArray* matches = [Contact objectsWithPredicate:predicate];!! // Find first 10 Contacts, sorted by name! NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];! NSFetchRequest* fetchRequest = [Contact fetchRequest];! [fetchRequest setFetchLimit:10];! [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];! NSArray* sortedContacts = [Contact objectsWithFetchRequest:fetchRequest];} 23

Wednesday, March 16, 2011

Page 24: Two Toasters - Presentation - RestKit for Rubyists

Database Seeding

// This is typically configured as a secondary target on your project// Dump your seed data out of your backend system in JSON format// Add to the project as resources// Run the secondary target in the Simulator- (void)seedTheDatabase {! // Setup the object manager! RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:@"http://restkit.org"];! objectManager.objectStore = [RKManagedObjectStore objectManagerWithStoreFilename:@"ContactsSeed.sqlite"];!! // Load all the data from the file contacts.json into a seed database! // The seeder will print instructions for how to copy the data to your app! RKObjectSeeder* seeder = [RKObjectSeeder objectSeederWithObjectManager:objectManager];! [seeder seedObjectsFromFiles:@"contacts.json", nil];! [seeder finalizeSeedingAndExit];}

24

Wednesday, March 16, 2011

Page 25: Two Toasters - Presentation - RestKit for Rubyists

25

Integration Points

Three20 Ruby on Rails

Wednesday, March 16, 2011

Page 26: Two Toasters - Presentation - RestKit for Rubyists

What’s next?

26

• Documentation & polish

• Object Mapper 2.0

• Offline Writes

• Object Streamer

• Conflict Resolution & Bi-directional Syncing

Wednesday, March 16, 2011

Page 27: Two Toasters - Presentation - RestKit for Rubyists

Thank You!http://restkit.org/

http://twitter.com/restkit

http://github.com/twotoasters/restkit

Wednesday, March 16, 2011