External Processes

CouchDB now allows for the ability to develop custom behaviors via processes that communicate over stdin and stdout. Requests to CouchDB that are captured by the external process handler are passed via JSON object to the external process over stdin and reads a JSON object from stdout. Without further ado...

JSON Requests

Requests capture information about the incoming HTTP request and transform it into a JSON object. I've formatted the object here, though in real life this object would contain no new lines and all embedded white space would be normalized to a single ' ' (space) character.

An example object:

    'body': 'undefined',
    'cookie': {
        '__utma': '96992031.3087658685658095000.1224404084.1226129950.1226169567.5',
        '__utmz': '96992031.1224404084.1.1.utmcsr'
    'form': {},
    'info': {
        'compact_running': False,
        'db_name': 'couchbox',
        'disk_size': 50559251,
        'doc_count': 9706,
        'doc_del_count': 0,
        'purge_seq': 0,
        'update_seq': 9706},
    'path': [],
    'query': {},
    'verb': 'GET'

In order:

JSON Response

The response object has five possible elements

While nothing breaks if you specify both a json and body member, it is undefined which response will be used. If you specify a Content-Type header in the headers member, it will override the default.

Common Pitfalls


Adding external processes is as easy as pie. Simply place key=command pairs in the [external] section of your local.ini and then map those handlers in the [httpd_db_handlers] section, like:

;Including [log] and [update_notification] for context

level = info

test = /usr/local/src/couchdb/test.py

_test = {couch_httpd_external, handle_external_req, <<"test">>}

;unique notifier name=/full/path/to/exe -with "cmd line arg"

This configuration will make the /usr/local/src/couchdb/test.py responsible for handling requests from the url:${dbname}/_test

Example External Process

Here is a complete Python external process that does a whole lot of nothing except show the mechanics.

#! /usr/bin/env python

import sys

    # Python 2.6
    import json
    # Prior to 2.6 requires simplejson
    import simplejson as json

def requests():
    # 'for line in sys.stdin' won't work here
    line = sys.stdin.readline()
    while line:
        yield json.loads(line)
        line = sys.stdin.readline()

def respond(code=200, data={}, headers={}):
    sys.stdout.write("%s\n" % json.dumps({"code": code, "json": data, "headers": headers}))

def main():
    for req in requests():
        respond(data={"qs": req["query"]})

if __name__ == "__main__":

last edited 2009-01-31 23:28:31 by PaulDavis