Monday, February 15, 2010

Simple CouchApp

‹prev | My Chain | next›

As I have been experimenting with CouchDB replication, I have grown enamored of the idea of replicating application as well as data. Today, I will give couchapp a try. I am not set up for any kind of Python work, so first up I need to able to run Python easy_installs. On Ubuntu, I need to:
sudo apt-get install python-setuptools
After that I can run sudo easy_install couchapp to install couchapp:
cstrom@whitefall:~$ sudo easy_install couchapp
Searching for couchapp
Reading http://pypi.python.org/simple/couchapp/
Reading http://github.com/couchapp/couchapp/tree/master
Best match: Couchapp 0.5.3
Downloading http://pypi.python.org/packages/source/C/Couchapp/Couchapp-0.5.3.tar.gz#md5=ee1ba536818307041d4640d6168c0fd4
Processing Couchapp-0.5.3.tar.gz
Running Couchapp-0.5.3/setup.py -q bdist_egg --dist-dir /tmp/easy_install-OsHEBm/Couchapp-0.5.3/egg-dist-tmp-gPkP1h
zip_safe flag not set; analyzing archive contents...
couchapp.utils: module references __file__
couchapp.generator: module references __file__
couchappext.compress.yuicompressor: module references __file__
couchappext.compress.compress_css: module references __file__
Adding Couchapp 0.5.3 to easy-install.pth file
Installing couchapp script to /usr/local/bin

Installed /usr/local/lib/python2.6/dist-packages/Couchapp-0.5.3-py2.6.egg
Processing dependencies for couchapp
Finished processing dependencies for couchapp
With that, I can generate a "hello world" couchapp. Since this is CouchDB, I will call this "relax":
cstrom@whitefall:~/repos$ couchapp generate relax && cd relax
In that directory, I find:
cstrom@whitefall:~/repos/relax$ ls -F
_attachments/ couchapp.json _id lists/ shows/ updates/ vendor/ views/
But what goes into these directories?

After consulting the documentation a bit, I need to add anonymous javascript functions into these directories. The names of the files will become attributes on the constructed design document and, hence, part of the URL to be accessed. First up, I create an shows/test.js file that returns a static HTML string:
function(req, doc) {
return "<h1>Testing</h1> <p>This is a test.</p>";
}
Then I push this to the same database that contains all of my meals and recipes:
cstrom@whitefall:~/repos/relax$ couchapp push http://localhost:5984/eee
[INFO] Visit your CouchApp here:
http://localhost:5984/eee/_design/relax/index.html
Before checking on that URL, I first check my existing design documents. I have a lot of them upon which my Sinatra relies heavily so I'd be very put out if they were touched. Happily, they were not and I now have a shiny (and relaxing) new design document:


There are no view functions (maps/reduces) as with the old meals and recipes design documents, but hopefully there is a show function with some very simplistic output:


With that working, what are the two parameters on the test.js function? The second one is the request object, which can be used to obtain query parameters:
function(doc, req) {
return "<h1>Testing</h1> <p>This is a test.</p>" +
"<p>query param foo=" + req.foo + "</p>";
}
When I access the page at http://localhost:5984/eee/_design/relax/_show/test?foo=bar, I don't get a value of "bar" as I expected. Instead, I get undefined:


I thought that would work. So if I can't get access to the query parameters directly on the request object passed into the anonymous function, how do I get access? Well, let's check the properties on the request object first:
function(doc, req) {
var keys = [];
for (var key in req) {
keys.push(key);
}


return "<h1>Testing</h1> <p>This is a test.</p>" +
"<p>query param foo=" + req.foo + "</p>" +
"<p>request object has:" + keys.join(', ') + "</p>";
}
This shows the following properties on the request object:


Ah, there is a query property in there. Hopefully I can get the query parameter from that:
function(doc, req) {
var keys = [];
for (var key in req) {
keys.push(key);
}

return "<h1>Testing</h1> <p>This is a test.</p>" +
"<p>query param foo=" + req.query.foo + "</p>" +
"<p>request object has:" + keys.join(', ') + "</p>";

}
Yup, there it is:


Cool. Well, that's the request object, what about the document object that is passed into the anonymous show function? To supply a particular document, the document ID needs to be passed at the end of the URL. To supply the test sequence document that I was using last night, the URL would be http://localhost:5984/eee/_design/relax/_show/test/test-sequence?foo=bar. As it is written right now, the show function is not actually doing anything with the document. To display the number attribute of the test-sequence document, I alter the show function:
function(doc, req) {
var keys = [];
for (var key in req) {
keys.push(key);
}

return "<h1>Testing</h1> <p>This is a test.</p>" +
"<p>Current number is: " + doc.number + "</p>" +

"<p>query param foo=" + req.query.foo + "</p>" +
"<p>request object has:" + keys.join(', ') + "</p>";
}
Now, accessing the URL shows the current sequence number:


That is pretty cool. Obviously, it would be a lot cooler if the show functions could display forms that could create and edit new CouchDB documents. This is just what couchapp promises. I will explore that more in a couple of days, but first...

I turn on my second machine et voilà:


The couchapp generated show document is automatically there.

Day #15

2 comments:

  1. Thank you for writing this! I have been having some trouble getting started with CouchApp as docs can be sparse. I look forward to your future posts on the matter and can't wait to read more.

    ReplyDelete
  2. The CouchDB book is a pretty good reference: http://books.couchdb.org/relax/ -- I'm relying on it and looking through the sofa code quite a bit trying to figure this out. That said, there's no substitution for actually doing it. I'm finding quite a large gap between what I think I know and what I really know when it comes time to writing this up!

    This has been great for my understanding and I'm thrilled someone else has found it useful :)

    ReplyDelete