Getting Started with CouchDB: A Simple Address Book Application

June 28, 2008 · 6 min read

I’ve recently installed CouchDB but, still being pretty new to this whole document store thing, I don’t really know what it can do or how to make it do it.

The best way to learn is to do. So I’m going to build a simple address book.

Investigation and technology choice

Since CouchDB speaks JSON, I’ll write the address book in JavaScript and HTML. And because CouchDB includes a built-in web server, I can serve the application from the same place I store the data. I’ll call the main file addressbook.html.

Peeking at the CouchDB configuration in /usr/local/etc/couchdb/couch.ini, I can see the web server’s document root is /usr/local/share/couchdb/www – that’s where addressbook.html will go.

I’ll also need a database for storing contacts. There’s a handy admin interface at /_utils/ that you can access through your browser by pointing it at the CouchDB server’s IP address and port.

CouchDB ships with a JavaScript wrapper at /_utils/script/couch.js, but it only talks to localhost. Since I’m accessing the page over the network, I’ll borrow some of its ideas and adapt them.

Implementation

First, create the database. Open the admin interface at /_utils/ and create a database called “addressbook”. That’s where our data will live.

The UI is a plain webpage with JavaScript, which keeps things simple. Here’s the starting point:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <!-- The javascript will live in addressbook.js -->
  <script src="http://aaa.bbb.ccc.ddd:5984/_utils/addressbook.js"></script>
  <title>Address Book</title>
</head>
<body>
  <h1>Address Book</h1>
  <div id="addressbook">
    <p id="loading">Loading... please wait...</p>
  </div>
</body>
</html>

Since I’ve been spoiled by ActiveRecord, I want something like var people = Person.find("all"); to return all records, and Person.find("123456-1234-1234-123456"); to fetch a specific one:

Person = {
  // Push the implementation details of the database into a
  // different object to keep Person clean.
  //
  database: AddressBook,
  find: function(id) {
    if(id == "all") {
      return this.database.allCards();
    } else {
      return this.database.openCard(id);
    }
  }
}

The AddressBook object abstracts the database connection away from Person. It provides two methods – allCards and openCard(id) – which talk to CouchDB and handle data marshalling:

AddressBook = {
  // Change this to point to your own CouchDB instance.
  uri: "http://craig-01.vm.xeriom.net:5984/addressbook/",

  _request: function(method, uri) {
    var req = new XMLHttpRequest();
    req.open(method, uri, false);
    req.send();
    return req;
  },

  // Fetch all address book cards.
  allCards: function() {
    var req = this._request("GET", this.uri + "_all_docs");
    var result = JSON.parse(req.responseText);
    if (req.status != 200)
      throw result;
    var allDocs = [];
    for(var offset in result.rows) {
      var id = result.rows[offset]["id"];
      var doc = this.openCard(id);
      allDocs[allDocs.length] = doc;
    }
    return allDocs;
  },

  // Fetch an individual address book card.
  openCard: function(id) {
    var req = this._request("GET", this.uri + id);
    if (req.status == 404)
      return null;
    var result = JSON.parse(req.responseText);
    if (req.status != 200)
      throw result;
    return result;
  }
}

I’m offloading JSON parsing to Yahoo’s JSON library. Pull it into the webpage and expose it in the global namespace:

<!-- Add this to the head of addressbook.html -->
<script src="http://yui.yahooapis.com/2.5.2/build/yahoo/yahoo-min.js"></script>
<script src="http://yui.yahooapis.com/2.5.2/build/json/json-min.js"></script>
// Make YUI JSON available in the global namespace.
// Add this to addressbook.js
JSON = YAHOO.lang.JSON;

The last piece is something to load all contacts and render them on the page. This uses window.onload, which is not ideal, but for a quick demo it does the job:

// This is horrible, I know, but it's just a simple example.
window.onload = function() {
  var addressbook = document.getElementById("addressbook");
  var personList = document.createElement("ul");
  for(var offset in people) {
    var person = people[offset];
    var personNode = document.createElement("li");
    var name = document.createTextNode(person.name);
    personNode.appendChild(name);
    personList.appendChild(personNode);
  }
  addressbook.removeChild(document.getElementById("loading"));
  addressbook.appendChild(personList);
}

That’s it – the application is ready. Upload addressbook.html and addressbook.js to the document root of the CouchDB server, open your browser, and navigate to http://aaa.bbb.ccc.ddd:5984/_utils/addressbook.html (replacing aaa.bbb.ccc.ddd with your CouchDB server’s IP address).

You’ll be greeted by a blank page that says “Address Book”. Not very impressive, right? But nothing’s wrong – there’s just no data in the database yet.

The admin interface at /_utils/ can also add documents. Navigate to the addressbook database and create a new document. When it asks for an ID, leave the field blank and it’ll auto-generate one. Add a field called name, click the green checkbox, then double-click the value and set it to your name in quotes (e.g. "Craig Webster"). Click the green arrow, hit “save document”, then refresh the address book page. Your new record should appear.

Moving forward

I’ve shown how to retrieve data from CouchDB using JavaScript, but data entry still happens through the admin interface. Watch this space for an upcoming article on manipulating the database from JavaScript so we can add contacts directly from the address book.

These posts are LLM-aided. Backbone, original writing, and structure by Craig. Research and editing by Craig + LLM. Proof-reading by Craig.