This is a tutorial on how to build a simple messaging app (we'll call it KMessenger) with Kumulos. Firstly, this tutorial will show you how to build a simple app that lets users register with your app and log in. Here's what it looks like:

Kumulos Sample Code Demo App

First we will be setting up our database tables to store user information, then creating some API methods to access the tables and finally integrating the generated code into our iPhone app.

To get started, create a new application in Kumulos. You can call it anything you like, but usually best to stick with your app name – in our case – 'KMessenger'.

Source Code

Download the accompanying source code for this tutorial here: KMessenger Source Code

The User Table

We need a users table to store all our application users. The table will store username, password, email and a device type that we'll use later. To create a new table, click the'Database Tables' tab, then click 'Add Table'.

Our table looks like this:

Kumulos Tutorial User Table

Notice we've indexed username and deviceType? This allows us to recall records from the database matching these fields much faster. It might not be noticeable on small datasets, but as soon as you get lots of users you'll see the difference. Once you've set up the table as above, click 'Save'. Remember to activate the table, this set's up the table on the database cluster so it's ready for API's to create and retrieve records.

The API Methods

For this tutorial we just need two API methods, userLogin and addNewUser. Fairly self explanatory what each of these methods do but here is how they are created; To add a new API method, select the third tab 'API Methods' and click on 'Add API Method'.

Adding a New User

To start off we just name our method and select a primary table. The primary table allows Kumulos to load in the table fields as suggested parameters. Remember you can create your own parameters to a method if you wish, by simply typing the name and pressing 'Add'.

New User API Title

For this method, we need four input parameters: username, password, email and deviceType.

New User API Input Parameters

If we drag a create action box into the action panel, Kumulos automatically hooks up the parameters to the table fields. We don't actually need to do anything else here, just click 'save'.

New User API Actions

Logging a User In

To log a user in, we use a select action with filters on both the username and password. After naming our method 'userLogin' we use username and password as parameters then just drag a select action and drop it onto the action panel. Then click '(add filter)'. Kumulos will add a filter for the first field, in this case 'username' and automatically match it with a parameter of the same name. Click the '(+ and)' link to add another filter then just select 'password' for both the field and parameter.

User Login API Method

Once you have created both these methods click 'Build API' on the API methods panel, Kumulos will build your API methods into server side code and also generate your Objective-C bindings. These bindings contain a static library file, two header files and a '.m' code file. Simply drag all these files into the Xcode project.

The iPhone Bit

Logging a User In

Lets look at the doLogin function in KSLogin.m. This method is called when we press the login button, in order to use the Kumulos class we need to include the Kumulos header file in KSLogin.h:

#include "Kumulos.h"

Now we can modify the doLogin method like so:

-(void)doLogin{
    //we want to log user in
    NSString* username = [(UITextField*)[[self view] viewWithTag:TEXTFIELD_UNAME] text];

    NSString* password = [(UITextField*)[[self view] viewWithTag:TEXTFIELD_PWORD] text];

    Kumulos* k = [[Kumulos alloc]init];
    [k setDelegate:self];

    [self showLoadingIndicator];
    [k userLoginWithUsername:username andPassword:[k md5:password]];
}

The first two lines of code simply grab the text field contents, this is the username and password we'll be passing to Kumulos. Next we simply create an instance of the Kumulos object and set it's delegate to the KSLogin class.

This is important, as it is the delegate class that is called when Kumulos API call is complete, and where we get the results of the API. We also show a loading indicator for user feedback – but this isn't by any means essential for the use of Kumulos.

Next we just call the API itself. Because Kumulos has generated our bindings alongside our API methods, the Kumulos object has a method for each API. You'll notice we've used the "md5" method of the Kumulos object to encode the password. This is just standard practice when storing users passwords in a database. We'll be extending the Kumulos object over time to include other useful functions like this. We could try and compile this now, but we would likely get a warning because our KSLogin class doesn't follow the KumulosDelegate protocol. to fix this, we just add the following in KSLogin.h:

@interface KSLogin : UIViewController <UITextFieldDelegate,KumulosDelegate> {

This is actually all we need to run the userLogin API method, but this isn't any use unless we get a response to verify the user login was successful. To do this we implement the protocol callback methods in our KSLogin class. For each API method we create in Kumulos, a corresponding callback method is created in the Objective-C Kumulos object.

In Our Kumulos.h file we can see the protocol definition:

@protocol KumulosDelegate <kumulosProxyDelegate>
@optional

- (void) kumulosAPI:(Kumulos*)kumulos apiOperation:(KSAPIOperation*)operation userLoginDidCompleteWithResult:(NSArray*)theResults;
- (void) kumulosAPI:(Kumulos*)kumulos apiOperation:(KSAPIOperation*)operation addNewUserDidCompleteWithResult:(NSNumber*)newRecordID;
@end

Here we see our userLogin callback method. Because we set the KSLogin class as the delegate for the Kumulos object, it will try and call the callback method on that class, so we just add the method to our KSLogin class:

- (void) kumulosAPI:(Kumulos*)kumulos apiOperation:(KSAPIOperation*)operation userLoginDidCompleteWithResult:(NSArray*)theResults{

    [self hideLoadingIndicator];

    UIAlertView* alert = [[UIAlertView alloc]init];
    [alert addButtonWithTitle:@"OK"];
    [alert setDelegate:nil];

    if ([theResults count]) {
        [alert setTitle:@"Success"];
        [alert setMessage:@"You are now logged in"];
    }else {
        [alert setTitle:@"Whoops"];
        [alert setMessage:@"Sorry we could not log you in."];
    }

    [alert show];
    [alert release];
    [kumulos release];
}

First we remove the loading indicator, then set up an alert view to let our user know if login has been successful. Because our API method simply selects all records where username and password match our input parameters, we just need to check to see if a record was returned. All Kumulos callbacks return an NSArray with the results, for a select action the rows are returned as NSDictionaries, for insert actions the NSArray will contain a single object which is an NSInteger – the new record's ID – and for update and delete actions the NSArray will contain a single NSInteger which is the number of records affected.

By checking if there are any objects in the NSArray we can determine if login was successful and alert the user. And that's it, we can now log a user in to our application.

Adding a New User

Next, let's take a look at our KSRegisterVC UIViewController. Again make sure you import the Kumulos header file in KSRegisterVC.h and set KSRegisterVC to follow the KumulosDelegate protocol. So, straight to the doRegister method:

-(void) doRegister{

    //Get values
    NSString* username  = [(UITextField*)[[self view] viewWithTag:TEXTFIELD_UNAME]text];
    NSString* password  = [(UITextField*)[[self view] viewWithTag:TEXTFIELD_PWORD]text];
    NSString* email     = [(UITextField*)[[self view] viewWithTag:TEXTFIELD_EMAIL]text];

    if (username == nil || password == nil || email == nil) {
        UIAlertView* alert = [[UIAlertView alloc]init];
        [alert addButtonWithTitle:@"OK"];
        [alert setDelegate:nil];
        [alert setTitle:@"Whoops"];
        [alert setMessage:@"You need to input all fields"];
        [alert show];
        [alert release];
        return;
    }

    //We want to register
    [self showLoadingIndicator];
    Kumulos* k = [[Kumulos alloc]init];
    [k setDelegate:self];
    [k addNewUserWithUsername:username andPassword:[k md5:password] andEmail:email andDeviceType:@"iOS"];
}

Just as before we get all the input values from text fields, then we perform some basic validation to ensure all fields are filled in. We show the loading indicator, initialise a Kumulos object, set the delegate and call the API method. All simple stuff, but as before we need to get the response back from Kumulos to provide some feedback:

- (void) kumulosAPI:(Kumulos*)kumulos apiOperation:(KSAPIOperation*)operation addNewUserDidCompleteWithResult:(NSNumber*)newRecordID{
    [self hideLoadingIndicator];
    [kumulos release];
    [self dismissModalViewControllerAnimated:YES];
}

All very self explanatory, hide the loading indicator, release the Kumulos object and dismiss the current controller.

Extras

Correctly Handling Failure

Sometimes, things might not go to plan and for one reason or another a Kumulos API call may fail. This can be handled gracefully by implementing the failure callback. Although this isn't part of the KumulosDelegate protocol, it is part of the KumulosProxyDelegate which KumulosDelegate extends. Its protocol syntax is as follows:

@protocol kumulosProxyDelegate <NSObject>
@optional
- (void) kumulosAPI:(kumulosProxy*)kumulos didFailWithError:(NSString*)theError;
@end

We can implement this callback in any method that follows the KumulosDelegate protocol, for example our KSLogin or KSRegisterVC class.

Debugging API Responses

It can be helpful to see exactly what Kumulos is returning to your API calls, you can configure Kumulos method calls to operate in debug mode which causes them to output useful information to the console. To enable this edit your Kumulos.m file and add the following after the KSOperation is initialised:

[newOp setDebugMode:YES];