Cocoa, JSON & Turbogears

This post discusses how to use Cocoa to communicate with Turbogears powered web-applications. The post is a follow up to my previous post that introduced my JSON Cocoa serialisation code.

The example Turbogears and Cocoa project is available from JSONTest.zip

A normal Turbogears controller method looks something like this:

    @turbogears.expose(template="jsontest.templates.test")
    def test(self, name = ‘Nobody’):
        return dict(greeting = ‘Hello ‘ + name)

HTTP GET and POST parameters reach the method as the method’s parameters and the method returns the result as a dictionary. The result can then be furher processed in the applications templates. The @turbogears.expose decorator defines which template will be used to process the result and produce the HTML page. You can tell a method to also return JSON formatted data by passing “allow_json=True” to the expose decorator. Now when the relevant turbogears url is accessed with “?tg_format=json” appended to the URL, a json document will get returned to the client.

This only allows the server to return JSON formatted data. It doesn’t allow it understand JSON formatted data that is sent to it. To do that I’ve created another decorator that takes JSON data from the HTTP request body if the Content-Type is text/javascript:

def JSON_INPUT(validators = {}):
    def decorator(fn):
        def newFunction(self, *args, **vargs):
            if cherrypy.request.headerMap['Content-Type'] == ‘text/javascript’:
                theBody = cherrypy.request.body.read()
                theDictionary = simplejson.read(theBody)
                theValidationKeys = set(theDictionary.keys()).intersection(set(validators.keys()))
                theItems = [(theKey, validators[theKey].to_python(theDictionary[theKey])) for theKey in theValidationKeys]
                theDictionary.update(dict(theItems))
                theDictionary = dict([(str(theItem[0]), theItem[1]) for theItem in theDictionary.items()])
                print theDictionary
                vargs.update(theDictionary)
            result = fn(self, *args, **vargs)
            return result
        return newFunction
    return decorator

To use this decorator it needs to be declared after the normal @turbogears.expose decorator. And thats it, your method can now send and receive JSON formatted data:

    @turbogears.expose(template="jsontest.templates.test", allow_json=True)
    @JSON_INPUT()
    def test(self, name = ‘Nobody’):
        return dict(greeting = ‘Hello ‘ + name)

Now here’s the fun part. Following is some Cocoa code to send a request to a turbogears server and handle the response. The code is just a simple HTTP POST with the HTTP body consisting of a JSON serialised NSDictionary. Also make sure the “Content-Type” is set correctly. The HTTP response is again just another JSON document that is deserialised into an NSDictionary. Of course this example code is very bad, no error checking and the HTTP POST is performed synchronously, don’t do this:

- (IBAction)actionTest:(id)inSender
{
NSDictionary *theRequestDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
    name, @"name",
    NULL];
//
NSURL *theURL = [NSURL URLWithString:@"http://localhost:8080/test/?tg_format=json"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0f];
[theRequest setHTTPMethod:@"POST"];
//
[theRequest setValue:@"text/javascript" forHTTPHeaderField:@"Content-Type"];
NSString *theBodyString = [[CJSONSerializer serializer] serializeDictionary:theRequestDictionary];
NSData *theBodyData = [theBodyString dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@", theBodyData);
[theRequest setHTTPBody:theBodyData];
//

NSURLResponse *theResponse = NULL;
NSError *theError = NULL;
NSData *theResponseData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&theResponse error:&theError];
NSString *theResponseString = [[[NSString alloc] initWithData:theResponseData encoding:NSUTF8StringEncoding] autorelease];
NSDictionary *theResponseDictionary = [[CJSONDeserializer deserializer] deserialize:theResponseString];
NSString *theGreeting = [theResponseDictionary objectForKey:@"greeting"];
[self setValue:theGreeting forKey:@"greeting"];
}
This entry was posted in Default and tagged . Bookmark the permalink.

Comments are closed.