Introducing RestKit

RestKit is an amazing Objective-C framework for iOS that aims to make interacting with RESTful web services simple, fast and fun. As said on its homepage:

It combines a clean, simple HTTP request/response API with a powerful object mapping system that reduces the amount of code you need to write to get stuff done.

RestKit provides several components:

An HTTP client component based on NSURLConnection. It’s not as feature-packed as ASIHTTPRequest1, but it does its part very well in most cases. It supports GETPOSTPUTDELETE, SSL & HTTP AUTH, multi-part, etc. It even provides a request queue to manage the HTTP requests(mostly implicitly), making them more memory and bandwidth efficient.

A powerful but elegant object mapping system, which uses idiomatic key-value coding mechanism to define and implement the round-trip transformation between JSON2 string and native Objective-C class. Well, the magic behind it is called SOCKit3.

A persistent layer built on top of the object mapping system, fully integrated with CoreData. Can be used as app’s primary data storage or just local cache.

Other than making another almighty monster its creators focus on the remote-local object (can be transient or persistent through CoreData) mapping. They made it through the ‘common things simple, others possible’ philosophy, which I always love.

RestKit has some documentations but not very well organized. Maybe it’s the biggest problem for beginners. So I’d like to list below some most useful solution recipes I’ve used in real world project, updated progressively.

**WARNING**: it will be incredibly long anyway.

Setting up

RestKit provides two ways to set up the RestKit client: RKClient and RKObjectManager. If you want to manually handle the return data you should use RKClient. Otherwise, if you want to use the RestKit object mapping system, then RKObjectManager is the one.

By using RKObjectManager you’ll map the web resources to local Objective-C objects, so you need not (and cannot) handle the return data explicitly. Instead you should handle data through the mapping system, which will be discussed below.

Modeling and Mapping

Now the object mapping system. Let’s start with the best practice in RESTful API backed mobile app development:

Analyze the business and make abstraction.

Design the RESTful API spec based on the first step, including all call endpoints, parameters and returning data in JSON format.

Mapping the API spec to native code in designated mobile platform.

Assuming we have a simple API named users/login, accepting POST request with 2 parameters: username and password, doing login check, and returning a encrypted access token and corresponding user object. And as a global convention we encapsulate the payload as response section in a JSON string which also contains a meta section for system level info such as status code and error message. So here it looks like:

{

"meta":{

"code":200

},

"response":{

"token":"931240153764834717 156605143238420655",

"user":{

"user_name":"soulhacker",

"..."

}

}

}

It’s simple but not trivial, and very representative. What will the mapping work? Have a look at the code first:

Line 1-35. Firstly we defined all needed model classes: fundamental ones first, ones that contain them next. Just follow the nature of the data structure within the API’s response data.Line 51-56. Use instances of RKObjectMapping class to define object mappings. Simple mappings are self explained. Note that RKObjectMapping provides several different mapXXX methods to suit different use cases. The key path in mapping definition fully follows Cocoa’s key path style (also support collection operators). Check its document and Apple’s Key Value Coding Guide for detail.Line 58-61. Complex object mappings are defined by mapKeyPath:toRelationship:withMapping: or similar methods. They map some key path to pre-defined object mappings. As seen in the code, the mapping to class UsersLogin contains simple mapping (line 59) and relationship mappings (line 60-61).Line 64-67. RKObjectManager provides loadObjectsAtResourcePath:objectMapping:delegate: method to do these steps in order: combine resource path with the global BaseURL (configured within the RKObjectManager singleton), load resource from web services, parse return data, transform to local objects according to pre-defined RKObjectMapping instance, at last call the delegate to handle result.Line 72-80. Delegate methods didLoadObjects and didFailWithError (required) are called after the object mapping process. Normally fetch the result object and do whatever you want.

Routing

The previous code list is neat except one part. Note line 64-66, in which we hard-code the API endpoint and parameters. In our login scenario it may not be a big problem, but for highly reused objects, repeatedly constructing GETPOSTPUTDELETE URLs by hand could be real pain in the ass. How about more object-oriented and more elegant way, just like the routing system in Ruby on Rails?

RestKit is most suitable for developers who has RoR background because of its Routing system which is highly alike to RoR’s, but built on Cocoa’s idiomatic key-value coding way. Here is the code sample:

// Then we can call the GET POST PUT DELETE verbs directly from object manager

User*me=[[Useralloc]init];

me.userName=@"soulhacker";

[[RKObjectManagersharedManager]postObject:medelegate:self];

User*sb2nuke=[[Useralloc]init];

sb2nuke.id=[NSNumbernumberWithInt:13];

[[RKObjectManagersharedManager]deleteObject:sb2nukedelegate:self];

Line 4 set the default route of User class, which means when you call object manager’s getObjectpostObjectputObjectdeleteObject methods the requests will go to @"/users/:id". This is a colon coded endpoint and what is after the colon is the name of a method in the route class, whose return value will replace the colon part.Line 5 set a special route for postObject method, which will override the setting in default route.Line 10 requests @"/users" with HTTP POST method and RestKit will transform me object into post data form as the way defined in object mapper of class User.Line 14 first call [sb2nuke id] method to get the value and replace :id with it, then requests @"/users/13" with HTTP DELETE method, which (should) remove the user object with id 13 from the server.

So you see, RestKit provides very flexible tools for RESTful web services integration: you can use the network layer and do all data mapping by hand, or you can use the object mapping to do it completely within local object system, or you can tuning it in some intermediate way. No matter which solution you choose remember to align the protocol between the server and client side, and don’t forget to verify them to the Android platform if necessary (there is no RestKit over there for now -_-).

Thus we’ve completed the first part of this introduction guide. Below we will discuss some facilities bundled in RestKit to make our life better.

The Request Queue

Request queue is the most important support player under the hood. RKRequestQueue is behind nearly all network access within RestKit and provides elegant solution for critical memory and bandwidth problems. RKRequestQueue wraps memory management within RestKit framework so you’ll never see any retainreleaseautorelease for RKRequestRKResponse instances. It let us developers focus on the business with very little concern about the memory management.

RKRequestQueue also provides seamless integration with Reachability API (in iOS System Configuration framework), pooling all requests when network is unavailable, and limiting concurrent requests when network becomes reachable to prevent overburden as well.

All the amazing features described above are working without knowing, and maybe the only visible part of RKRequestQueue is its request lifecycle management feature, by which you can cancel ongoing requests to prevent wasting the bandwidth. This is a common situation in mobile apps that when some user action generates a bunch of network requests and the following action actually makes those requests useless (e.g. the view for previous action is dismissed by the later action). By using RKRequestQueue we can do it very easily by its cancelRequest:cancelRequestsWithDelegate: and cancelAllRequests:` methods. And remember that whether and when to call them is fully determined by developers so you can choose the strategy wisely according to the different scenarios. Here is the simplest sample:

-(void)viewWillAppear:(BOOL)animated{

[RKClientsharedClient]get:@"users/self"delegate:self];

}

-(void)viewWillDisappear:(BOOL)animated{

[[RKRequestQueuesharedQueue]cancelRequestsWithDelegate:self];

}

The cancelRequestsWithDelegate: method cancel all requests that current controller is delegate for. If there are no one processing it’ll do nothing.

The last but not least. What [RKRequestQueue sharedQueue] returns is the default queue which created automatically when the RestKit client initialized. In most real world apps it’s not enough. For example we may need a queue to handle special resource intensive tasks in a background thread, such as data uploading/downloading, while the default queue keep working for responding user actions. It’s easy:

Reachability

Reachability is the problem all mobile apps have to face and of course iOS provides solution for that, well, sort of. The problem is: SCNetworkReachability (in SystemConfiguration framework) is implemented as low level C APIs and not so easy to use. Fortunately RestKit is bundled with a very straight-forward Objective-C wrapper for that, the RKReachabilityObserver.

When RKClient (or RKObjectManager) is initialized with some base URL, RestKit automatically initializes an instance of RKReachabilityObserver targeted at the host specified in the base URL and can be accessed via baseURLReachabilityObserver property. This observer also automatically registers RKReachabilityStateChangedNotification events in the default notification center. So in most cases we can use it in very simple way:

Sending Multi-part Data

Sending multi-part data through HTTP requests is very common requirement and incredibly difficult in most programming languages. RestKit uses RKParams and RKParamsAttachment to handle that problem. RKParams is the container that can hold any kinds of parameters. For simple data type it works just like a NSDictionary, and for multi-part data it can wrap NSData and/or RKParamsAttachment objects. Both RKParams and RKParamsAttachment are MIME type friendly. The following self-explained code sample shows all:

Background Upload/Download

iOS supported multi-tasking since 4.0 but it’s a highly restricted support and there are so many misconceptions among the users and even developers. I would strongly suggest Fraser Speirs’ excellent blog which explains all about iOS multi-tasking.

RestKit can seamlessly facilitate multi-tasking to prevent important long-time requests being interrupted by user switching out of the app. The key is the backgroundPolicy property of RKRequest which can be one of 4 enum values:

RKRequestBackgroundPolicyNone: the default value, do nothing for backgrounding;

RKRequestBackgroundPolicyCancel: cancel the request when app switches to background;

RKRequestBackgroundPolicyContinue: continue the request in background;

RKRequestBackgroundPolicyRequeue: place the request back to the queue for next activation.

So to make a request continue to work in background, just set its backgroundPolicy property as below:

Conclusion

RestKit is a clean and elegant solution for iOS app to interact with RESTful web services. It encapsulates many everyday work into a tiny yet powerful framework and extremely easy to use. Suggest every iOS developers to give it a try.