I'm in the process of blogging my experiences using the Cappuccino JavaScript framework and CherryPy, a Python web application project. The first post can be found here.
Cappuccino is designed to provide an application-like interface inside a web browser. As a result, when you're building a Cappuccino application, instead of the server providing a sequence of pages to view, the server is providing data (usually using JSON) that the Cappuccino application running in the browser retrieves and displays. For all practical purposes, using Cappuccino is very like old-fashioned client server programming with the client written in Objective-J and the server, in this case, written in Python.
In this post we'll focus on changing the Cappuccino "Hello World" application so that it retrieves it's message from the server using JSON. No, it's not a particularly exiting application but it has the virtue of being simple and fundamental: Once it's possible to act on JSON data from the server, the rest is just details.
First, we'll change the client side Objective-J code. We need to add the following two lines to the end applicationDidFinishLauching: method of our AppController in AppController.j
var request = [CPURLRequest requestWithURL:"getLabel"];
var connection = [CPURLConnection connectionWithRequest:request delegate:self];
The first line creates a CPURLRequest for the "getLabel" URL from the server. The second line actually makes the connection to the server using that request object. Like it's inspiration, Cocoa, Cappuccino makes heavy use of the delegate pattern. In this case we pass our AppController object as the delegate for the CPURLConnection. There are two methods that the CPURLConnection may call on the delegate. We'll add those next:
- (void)connection:(CPURLConnection) connection didReceiveData:(CPString)data { var result = CPJSObjectCreateWithJSON(data); [label setStringValue:result.label] } - (void)connection:(CPURLConnection)connection didFailWithError:(CPString)error { [label setStringValue:@"Label Did Fail With Error"] }
The method "connection:didReceiveData:" is called with the original connection object (useful to distinguish between multiple pending connections) and the data that the server provided. The "connection:didFailWithError" is called if the connection failed for some reason.
For now, we'll simply change the label when the connection completes. If the connection fails, we'll note that. If the connection does receive data, we'll use that data to change the label. To do this, we use a CPJSObjectCreateWithJSON(data) object. Once we've done that, we can retrieve the "label" attribute of the result and display it.
There's one other thing that we need to do on the client side for all of this to work. In the original AppController.j, the label object is a local variable. Since other methods of our AppController object need to access that object, we need to make it an instance object. We do this by adding the following line to the "@implementation AppController" stanza in AppController.j:
CPTextField label;
We also need to remove the "var" qualifier from the first appearance of the label variable in "applicationDidFinishLaunching:"
The server side is even simpler. We simply need to add a method that will respond to the "getLabel" request that the client will make. We do this by adding a "getLabel"
method to the root CherryPy object:
@cherrypy.expose
def getLabel(self):
data = {"label":"Server Hello" }
return simplejson.dumps(data)
In that method, we'll create the Python dictionary that we'll return. It has one attribute/key "label" which we'll set to the string "Server Hello". Then we use the Python simplejson to convert that object to a JSON string which we return.
We've seen that it's fairly easy to communicate between the Cappuccino client and the CherryPy server. Next we'll start looking at building a somewhat more elaborate client application based on data returned from the server.
Post a Comment