Let’s first have a look at the final result. You can follow along by installing a version of couchapp and CouchDB of course. Then go to the program’s Github repository, clone the app, push it into CouchDB and launch the URL:
By pointing your Web browser at the URL given you by
couchapp, you’ll be
redirected to a
show function, from which you drag the generated bookmarklet
URL to your browser bar: (I have to “generate” the bookmarklet for you because
it contains the URL to your CouchDB instance; the show function determines the
full path and creates the bookmarklet containing that.)
Go ahead and drag the link into your bookmarks bar: mine is shown as the little recycle symbol. When you’ve done that, click on view all bookmarks, which will take you to the paginated list of the bookmarks stored in your CouchDB. (Yes, there are three there already. :-)
Clicking on the greater symbol takes you to a page describing the bookmark. Click on the bookmark title to take you to the URL saved with the bookmark. Within the description page, click on the “delete bookmark” to kill the document.
When visiting a site you wish to bookmark, press on the bookmarklet you saved in your bookmark bar when on the page. The text you select on the page becomes the bookmark’s description, and you’ll be propted to enter a list of (white space or comma-separated) tags for the page.
The bookmark is saved into CouchDB with a shortish
_id (swiped from Jan’s
io), whereupon you get a confirmation page. (I’d have liked to have the
update handler return a 302 redirection to the browser, but that isn’t
possible with CouchDB 0.11.)
The resulting bookmark looks like this:
One URL you may like to see is produced by a couchapp list:
/_design/app/_list/bookmarksfile/all produces a
bookmarks.html file you
can import into some Web browsers. Now that we’ve seen the app at work, let me
discuss its innards a bit.
I find that there is little documentation about couchapps, which is fair enough if you believe in “read the source” strategies, so I’ve created this trivial couchapp, and I’m going to point out the things I find most interesting, or situations where I had a hard time understanding what happens in couchapps.
Del.icio.us is a service which lets me submit, describe, and tag URLs I find interesting. I can share these with the rest of the world or mark URLs as being private. They have a sexy Web interface with which I can create and manage my bookmarks, and there exist dozens of bookmarklets and clients for managing them. They also have an API.
The del.icio.us API allows me to submit an authenticated HTTP GET request with URL-encoded parameters containing the data for the bookmark I want to add to my collection. As an example, I can point any HTTP client (e.g. my Web browser) at a URL like
and create a new bookmark.
I thought it would be trivial to implement the del.icio.us API on top of a CouchDB database, which would have had the great advantage that I could use any of the dozens of del.icio.us clients to drop bookmarks into my CouchDB. Unfortunately, the guys over at del.icio.us decided to implement a not-so- REST-y interface to their service; to add a new bookmark, del.icio.us uses an HTTP GET request instead of a POST or a PUT request.
Without some sort of middleware which converts a GET request to a POST, there
is no way to add a document to a CouchDB database – it must be either a POST
or a PUT request. I can call an update handler, but update handlers in CouchDB
support POST and PUT only, and Jan Lehnardt quickly pointed out in no
uncertain terms that I was barking up the wrong tree, trying to GET into an
update handler. He was right in pointing out on
#couchdb that I was trying
to circumvent REST principles. (And I’m grateful to him for having put me
Couchapp provides helper macros for getting code into your show and list functions. If you look at the file
// !json templates.index
That is parsed by the
couchapp utility when you invoke a
push and the
content of the file
templates/index.html is inserted into our
#include in C, for example. Go ahead and view the
app design document with Futon. The file’s content becomes a JSON object
templates with an name
index and as value, the content of the file.
A similar macro facility called
Files in the
_attachmentsdirectory are dumped into your CouchDB database as attachments. You’ll note I’ve stored the CSS for the HTML in such an attachment, for example.
I can have
couchappadd documents to the CouchDB database; see three examples in the
_docsdirectory. (This is why you get three bookmarks in your database when you push my simple app into your CouchDB.)
lib/file-system hierarchy are added to the design document, from which you can load them by requiring them, as in
var mustache = require("lib/mustache");. Omit the
.jsextension when doing so, or CouchDB complains about infinite recursion or something similar.
Couchapp contains a lot more magic: invoke
couchapp generate whatever and
explore the files created for you in the file system!
You’ll note I make some use of mustache.js – an indespensible templating system which thankfully allows me to keep code and HTML separate from eachother. Jan recently wrote a bit more about mustache.js, and the project’s README contains the rest of what you need to get started.
Import from del.icio.us
You can import your existing del.icio.us bookmarks rather easily by grabbing
an XML stream containing your own bookmarks and dumping that into a file
Let’s massage that XML with the following small program
delicious2couchdb.pl) by “translating” the XML entities to corresponding
JSON objects ready for CouchDB:
The format produced by
delicious2couchdb.pl is ready to be POSTed
into CouchDB’s _bulk_docs API:
@- is for curl: data is read from the named file,
and as the file is a single dash, curl reads the data from standard input.
There is a lot more to discover here, and I’d like to point out some neat Couch Apps:
- Jan Lehnardt’s io (mentioned above already) is a CouchDB-based URL shortener.
- J Chris A. created [sofa], a CouchDB-based blog, which is [what he uses].
- [Taskr] is a task-tracking app by J Chris A.
- More at [CouchApp.org]
The chapter on [Standalone Applications] in [CouchDB: The Definitive Guide] talks a bit about Couch Apps, and I don’t want you to miss my [CouchDB Reference Card]
: : http://jchrisa.net/drl/_design/sofa/_list/index/recent-posts?descending=true&limit=5 : http://github.com/jchris/taskr : http://couchapp.org/ : http://books.couchdb.org/relax/example-app/standalone-applications : http://books.couchdb.org/relax/ : /2010/04/20/the-antepenultimate-couchdb-reference-card/