Connecting to MongoHq API with RestKit

Exclusive offer: get 50% off this eBook here
RestKit for iOS

RestKit for iOS — Save 50%

Link your apps and web services using RestKit with this book and ebook

$20.99    $10.50
by Taras Kalapun | September 2013 | Open Source

In this article by Taras Kalapun, the author of RestKit for iOS, discusses how to connect to MonoHq API with RestKit. While performing a request operation, the object manager will use the base URL and the provided request path, to construct the NSURL object with [NSURL URLWithString:relativeToURL:]. The way this method evaluates the relativity of the URL can sometimes be confusing and surprising, and one can experience a lot of errors regarding this. For example, a small part of the AFNetworking documentation is provided, so one can better understand how the base URL and different paths interact.

(For more resources related to this topic, see here.)

Let's take a base URL:

NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];

Now:

[NSURL URLWithString:@"foo" relativeToURL:baseURL]; // Will give us http://example.com/v1/foo [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // -> http://example.com/v1/foo?bar=baz [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // -> http://example.com/foo [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // -> http://example.com/v1/foo [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // -> http://example.com/foo/ [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // -> http://example2.com/

Having the knowledge of what an object manager is, let's try to apply it in a real-life example.

Before proceeding, it is highly recommend that we check the actual documentation on REST API of MongoHQ. The current one is at the following link:

http://support.mongohq.com/mongohq-api/introduction.html

As there are no strict rules on REST API, every API is different and does a number of things in its own way. MongoHQ API is not an exception. In addition, it is currently in "beta" stage.

Some of the non-standard things one can find in it are as follows:

  • The API key should be provided as a parameter with every request. There is an undocumented way of how to provide it in Headers, which is a more common approach.
  • Sometimes, if you get an error with the status code returned as 200 (OK), which is not according to REST standards, the normal way would be to return something in 4xx, which is stated as a client error.
  • Sometimes, while the output of an error message is a JSON string, the HTTP response Content-type header is set as text/plain.

To use the API, one will need a valid API Key. You can easily get one for free following a simple guideline recommended by the MongoHQ team:

  1. Sign up for an account at http://MongoHQ.com.
  2. Once logged in, click on the My Account drop-down menu at the top-right corner and select Account Settings.
  3. Look for the section labeled API Token. From there, take your token.
  4. We will put the API key into the MongoHQ-API-Token HTTP header. The following screenshot shows where one can find the API token key:

    API Token on Account Info page

So let's set up our configuration using the following steps:

You can use the AppDelegate class for putting the code, while I recommend using a separate MongoHqApi class for such App/API logic separation.

First, let's set up our object manager with the following code:

- (void)setupObjectManager { NSString *baseUrl = @"https://api.mongohq.com"; AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:
[NSURL URLWithString:baseUrl]]; NSString *apiKey = @"MY_API_KEY"; [httpClient setDefaultHeader:@"MongoHQ-API-Token" value:apiKey]; RKObjectManager *manager = [[RKObjectManager alloc]
initWithHTTPClient:httpClient]; [RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class]
forMIMEType:@"text/plain"]; [manager.HTTPClient registerHTTPOperationClass:
[AFJSONRequestOperation class]]; [manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON]; manager.requestSerializationMIMEType = RKMIMETypeJSON; [RKObjectManager setSharedManager:manager]; }

  1. Let's look at the code line by line and set the base URL. Remember not to put a slash (/) at the end, otherwise, you might have a problem with response mapping:

    NSString *baseUrl = @"https://api.mongohq.com";

  2. Initialize the HTTP client with baseUrl:

    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL
    URLWithString:baseUrl]];

  3. Set a few properties for our HTTP client, such as the API key in the header:

    NSString *apiKey = @"MY_API_KEY"; [httpClient setDefaultHeader:@"MongoHQ-API-Token" value:apiKey];

    For the real-world app, one can show an Enter Api Key view controller to the user, and use a NSUserDefaults or a keychain to store and retrieve it.

  4. And initialize the RKObjectManager with our HTTP client:

    RKObjectManager *manager = [[RKObjectManager alloc]
    initWithHTTPClient:httpClient];

  5. MongoHQ APIs sometimes return errors in text/plain, thus we explicitly will add text/plain as a JSON content type to properly parse errors:

    [RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class]
    forMIMEType:@"text/plain"];

  6. Register JSONRequestOperation to parse JSON in requests:

    [manager.HTTPClient registerHTTPOperationClass:[AFJSONRequestOperation
    class]];

  7. State that we are accepting JSON content type:

    [manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];

  8. Configure so that we want the outgoing objects to be serialized into JSON:

    manager.requestSerializationMIMEType = RKMIMETypeJSON;

  9. Finally, set the shared instance of the object manager, so that we can easily re-use it later:

    [RKObjectManager setSharedManager:manager];

Sending requests with object manager

Next, we want to query our databases. Let's first see how a database request will show us the output in JSON. To check this, go to http://api.mongohq.com/databases?_apikey=YOUR_API_KEY in your web browser YOUR_API_KEY. If a JSON-formatter extension (https://github.com/rfletcher/safari-json-formatter) is installed in your Safari browser, you will probably see the output shown in the following screenshot.

JSON response from API

As we see, the JSON representation of one database is:

[ { "hostname": "sandbox.mongohq.com", "name": "Test", "plan": "Sandbox", "port": 10097, "shared": true } ]

Therefore, our possible MDatabase class could look like:

@interface MDatabase : NSObject @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *plan; @property (nonatomic, strong) NSString *hostname; @property (nonatomic, strong) NSNumber *port; @end

We can also modify the @implementation section to override the description method, which will help us while debugging the application and printing the object:

// in @implementation MDatabase - (NSString *)description { return [NSString stringWithFormat:@"%@ on %@ @ %@:%@", self.name, self.plan, self.hostname, self.port]; }

Now let's set up a mapping for it:

- (void)setupDatabaseMappings { RKObjectManager *manager = [RKObjectManager sharedManager]; Class itemClass = [MDatabase class]; NSString *itemsPath = @"/databases"; RKObjectMapping *mapping = [RKObjectMapping
mappingForClass:itemClass]; [mapping addAttributeMappingsFromArray:@[@"name", @"plan",
@"hostname", @"port"]]; NSString *keyPath = nil; NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass
(RKStatusCodeClassSuccessful); RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodGET pathPattern:itemsPath keyPath:keyPath statusCodes:statusCodes]; [manager addResponseDescriptor:responseDescriptor]; }

Let's look at the mapping setup line by line:

  1. First, we define a class, which we will use to map to:

    Class itemClass = [MDatabase class];

  2. And the endpoint we plan to request for getting a list of objects:

    NSString *itemsPath = @"/databases";

  3. Then we create the RKObjectMapping mapping for our object class:

    RKObjectMapping *mapping = [RKObjectMapping mappingForClass:itemClass];

  4. If the names of JSON fields and class properties are the same, we will use an addAttributeMappingsFromArray method and provide the array of properties:

    [mapping addAttributeMappingsFromArray:@[@"name", @"plan", @"hostname",
    @"port"]];

  5. The root JSON key path in our case is nil. It means that there won't be one.

    NSString *keyPath = nil;

  6. The mapping will be triggered if a response status code is anything in 2xx:

    NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass
    (RKStatusCodeClassSuccessful);

  7. Putting it all together in response descriptor (for a GET request method):

    RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodGET pathPattern:itemsPath keyPath:keyPath statusCodes:statusCodes];

  8. Add response descriptor to our shared manager:

    RKObjectManager *manager = [RKObjectManager sharedManager]; [manager addResponseDescriptor:responseDescriptor];

Sometimes, depending on the architectural decision, it's nicer to put the mapping definition as part of a model object, and later call it like [MDatabase mapping], but for the sake of simplicity, we will put the mapping in line with RestKit configuration.

The actual code that loads the database list will look like:

RKObjectManager *manager = [RKObjectManager sharedManager]; [manager getObjectsAtPath:@"/databases" parameters:nil success:^(RKObjectRequestOperation *operation,
RKMappingResult *mappingResult) { NSLog(@"Loaded databases: %@", [mappingResult array]); } failure:^(RKObjectRequestOperation *operation,
NSError *error) { NSLog(@"Error: %@", [error localizedDescription]) }];

As you may have noticed, the method is quite simple to use and it uses block-based APIs for callbacks, which greatly improves the code readability, compared to using delegates, especially if there is more than one network request in a class. A possible implementation of a table view that loads and shows the list of databases will look like the following screenshot:

View of loaded Database items

Summary

In this article, we learned how to set up the RestKit library to work for our web service, we talked about sending requests, getting responses, and how to do object manipulations. We also talked about simplifying the requests by introducing routing. In addition, we discussed how integration with UI can be done and created forms.

Resources for Article:


Further resources on this subject:


RestKit for iOS Link your apps and web services using RestKit with this book and ebook
Published: September 2013
eBook Price: $20.99
Book Price: $34.99
See more
Select your format and quantity:

About the Author :


Taras Kalapun

Taras Kalapun has more than 10 years experience as a Software Developer and Consultant in Mobile and Web. His background spans numerous technologies, programming languages, and databases. He was involved in developing more than 100 iOS projects and web services, as well as project management activities. In addition, he managed teams of software developers who all wanted to kill him. Through his mentoring, tech leading, troubleshooting, and code reviewing, he discovered that teaching by example resulted in more effective software development. A method he supplemented with, "Stop trying to reinvent the wheel"—a favorite phrase he used to tell young software developers.

He has worked at a number of IT companies across Europe including Ukrtelecom, a national Ukrainian telecommunication company; Ciklum, a Dutch outstuffing company headquartered in Ukraine; and Xaton, an Amsterdam software development company, in addition to freelance projects.

Occasionally he publishes small how-to articles on solving development problems and impedances on his blog, http://kalapun.com, some of which progressed to the development of this book.

Books From Packt


 Unity iOS Game Development Beginners Guide
Unity iOS Game Development Beginners Guide

 Flash iOS Apps Cookbook
Flash iOS Apps Cookbook

 iOS 5 Essentials
iOS 5 Essentials

 RubyMotion iOS Development Essentials
RubyMotion iOS Development Essentials

iOS Development using MonoTouch Cookbook
iOS Development using MonoTouch Cookbook

 iOS and OS X Network Programming Cookbook
iOS and OS X Network Programming Cookbook

Core Data iOS Essentials
Core Data iOS Essentials

 UDK iOS Game Development Beginner's Guide
UDK iOS Game Development Beginner's Guide


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
F
j
w
h
f
D
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software