Sevenforge Sevenforge by Curtis Spencer home

Pillowtalk, an ANSI C API for CouchDB

Download

July 13, 2009 Download Pillowtalk 0.0.1 Source

Overview

For those that don't know, [CouchDB] (http://couchdb.apache.org "CouchDB") is an exciting document oriented database that is built upon Erlang. It uses JSON as its data format and HTTP to communicate with clients. These two features are especially exciting because they create a platform agnostic way to pass around data and a horizontally scalable communication mechanism.

Library Design

Pillowtalk is meant to be as lightweight as possible, building mainly off the functionalities of both libcurl and yajl. The JSON parsing is optional. Your C code can either interact with raw json or use the pt_node_t. The pt_node_t is great for modifying JSON programmatically such as adding elements to an array in an existing document or adding key/value pairs to a map. Memory management is handled internally inside of Pillowtalk with a few types of free methods exposed. Also, I didn't try to mirror all of the functionality of CouchDB as named methods, but rather expose the lower level HTTP methods available, so the client can simply set the target and (optionally) pass JSON to that target using GET,PUT,DELETE,etc.

As we all know, C is not as concise as some other languages in the room, so this example may feel a little verbose.

An Example

In this example, we want to deal with pop culture franchises. An example of the JSON we will work with is.

{
  "_id": "star_wars",
  "movies" : {
    "Star Wars Episode IV": {
      "characters": ["Luke Skywalker","Han Solo","Obi Wan Kenobi"]
    }
  }
}

Setup

First you want to ensure to properly initialize pillowtalk. pt_init along with pt_cleanup are not thread safe, so make sure you call them before (or after) you start spawning threads.

pt_init();

Next we want to start building up some JSON to put in our CouchDB database. We can either build this up using pillowtalk_from_json or using the generator methods. Both procedures are shown below.

Parsing JSON from Raw String

const char* star_wars = "{\"_id\":\"star_wars\",\"movies\":{\"Star Wars Episode IV\":{\"characters\": [\"Luke Skywalker\",\"Han Solo\",\"Obi Wan Kenobi\"]}}}";
pt_node_t* root = pt_from_json(star_wars);

Generating JSON using Pillowtalk Functions

pt_node_t* root = pt_map_new();

pt_map_set(root,"_id",pt_string_new("star_wars"));
pt_node_t* movies = pt_map_new();
pt_map_set(root,"movies",movies);

// build movie subdocument
pt_node_t* ep4 = pt_map_new();

// build characters array
pt_node_t* ep4_chars = pt_array_new();
pt_array_push_back(ep4_chars,pt_string_new("Luke Skywalker"));
pt_array_push_back(ep4_chars,pt_string_new("Han Solo"));
pt_array_push_back(ep4_chars,pt_string_new("Obi Wan Kenobi"));
pt_map_set(ep4,"characters", ep4_chars);
pt_map_set(movies,"Star Wars Episode IV",ep4);

Now that we have some JSON built up we can play with some of the CouchDB methods So first let's make a database:

pt_response_t* response = NULL;
response = pt_delete("http://localhost:5984/pillowtalk_basics");
pt_free_response(response);
response = pt_put("http://localhost:5984/pillowtalk_basics",NULL);
pt_free_response(response);

Now we can take our built up JSON object and put it into the database. For now, I only have support for PUT using named documents.

response = pt_put("http://localhost:5984/pillowtalk_basics/star_wars",root);
assert(response->response_code == 201);
pt_free_response(response);

Working with Documents in the Database

The star_wars document is in the database, so what happens when we want to retrieve and modify that document. First, let's retrieve the document from the database using pt_get

response = pt_get("http://localhost:5984/pillowtalk_basics/star_wars");
assert(response->response_code == 200);

Once we have a response object we can start using the node reader methods to get information.

pt_node_t* doc = response->root;
const char* id = pt_string_get(pt_map_get(doc,"_id"));
assert(!strcmp(id,"star_wars"));

int array_len = pt_array_len(pt_map_get(pt_map_get(pt_map_get(doc,"movies"),"Star Wars Episode IV"),"characters"));
assert(array_len == 3);

As the last part of this example, let's add Princess Leia to our list of characters, add a year to the movie, and put back a new revision of the document into the database.

pt_node_t* ep4_node = pt_map_get(pt_map_get(doc,"movies"),"Star Wars Episode IV");
pt_node_t* characters_node = pt_map_get(ep4_node,"characters");
int array_len = pt_array_len(characters_node);
assert(array_len == 3);

pt_map_set(ep4_node,"year",pt_string_new("1977"));
pt_array_push_back(characters_node,pt_string_new("Princess Leia"));
pt_response_t* put_response = pt_put("http://localhost:5984/pillowtalk_basics/star_wars", doc);

You can see the end to end example file over at github: basic.c

Future

A lot more features are necessary for Pillowtalk to support everything CouchDB is capable of. Namely, POST and attachment support is next on the list. Please let me know if you give this a try. Please file tickets over at github or you can find me on Twitter or Freenode as @jubos.


Fork me on GitHub