Introduction to CouchDB with .NET part 3: starting with the CouchDB HTTP API

Introduction

In the previous post we looked at the CouchDB administrative UI called Fauxton. The UI that shipped with earlier versions of CouchDB is called Futon so you will still come across that name if you work with older CouchDB projects. Fauxton is quite easy and straightforward to use. The database section allows us to create, update and delete databases and documents. Many functions are meant to be handled by database admins such as CouchDB users, access rights, processes and configuration.

In this post we’ll start exploring the CouchDB HTTP-based API.

The CouchDB HTTP API

We saw that the Fauxton UI starts on the localhost endpoint http://localhost:5984/_utils/ . It responds with a HTML page. However, that URL is also the gateway into a HTTP-based API which communicates heavily with JSON web requests and responses. The general rule is that the URL includes the resource on which we want to execute some operation. The type of operation is governed by the HTTP verb such as GET, POST, PUT etc. We’re also expecting a web response from a web request. Responses will come in the form of HTTP status codes such as 200 OK, 201 Created and 500 Internal Server Error. The web responses can often also include a body with a message in the form of a JSON or XML string. This is nothing special, that’s how HTTP-based API’s are supposed to work and the CouchDB API follows these rules. We can get a couple of hints about the API endpoints from Fauxton actually. The UI header includes a button called API which opens a small dialog with a URL. Here’s an example from the Databases section:

API URL to get all databases in CouchDB

That API endpoint returns all databases of course. Copy the URL and open it in a web browser. You should get a JSON response similar to the following:

["_global_changes","_replicator","_users","customers"]

…i.e. an array of strings with the database names.

The following example appears after selecting a specific database:

API URL to get all documents within a database

The _all_docs endpoint of a database returns the same basic set of properties of all documents that we see in the UI:

{"total_rows":2,"offset":0,"rows":[
{"id":"0c458e911e3ff5b4e423bfe06c00133c","key":"0c458e911e3ff5b4e423bfe06c00133c","value":{"rev":"5-db3fe5937ed8ee9de36aaddc8ab3647e"}},
{"id":"77802a7eaffab7458a00f1f6cf00027c","key":"77802a7eaffab7458a00f1f6cf00027c","value":{"rev":"2-303ba1f5ada852ba09de8a6f6d4bed2e"}}
]}

Check the Include Docs option in the UI and open the API dialog again. The URL will be updated to the following:

http://localhost:5984/customers/_all_docs?include_docs=true&conflicts=true

…which returns a more complete set of properties from each document:

{  
   "total_rows":2,
   "offset":0,
   "rows":[  
      {  
         "id":"0c458e911e3ff5b4e423bfe06c00133c",
         "key":"0c458e911e3ff5b4e423bfe06c00133c",
         "value":{  
            "rev":"5-db3fe5937ed8ee9de36aaddc8ab3647e"
         },
         "doc":{  
            "_id":"0c458e911e3ff5b4e423bfe06c00133c",
            "_rev":"5-db3fe5937ed8ee9de36aaddc8ab3647e",
            "name":"New customer Inc",
            "preferred":false,
            "address":{  
               "street":"New street",
               "city":"Birmingham",
               "country":"UK",
               "postal_code":22222
            },
            "telephone":{  
               "office":"34543534",
               "sales":"576545645",
               "customer_care":"456456567"
            },
            "year_joined":2017,
            "current_status":"approved",
            "_attachments":{  
               "Administrative databases created on single node CouchDB installation.PNG":{  
                  "content_type":"image/png",
                  "revpos":4,
                  "digest":"md5-zHrwohh+oRdL29TExyrhrA==",
                  "length":33926,
                  "stub":true
               }
            }
         }
      },
      {  
         "id":"77802a7eaffab7458a00f1f6cf00027c",
         "key":"77802a7eaffab7458a00f1f6cf00027c",
         "value":{  
            "rev":"2-303ba1f5ada852ba09de8a6f6d4bed2e"
         },
         "doc":{  
            "_id":"77802a7eaffab7458a00f1f6cf00027c",
            "_rev":"2-303ba1f5ada852ba09de8a6f6d4bed2e",
            "name":"Great customer Inc",
            "preferred":true,
            "address":{  
               "street":"Victory avenue",
               "city":"New York",
               "country":"USA",
               "postal_code":11111
            },
            "telephone":{  
               "office":"34543534",
               "sales":"576545645",
               "customer_care":"456456567"
            },
            "year_joined":2015
         }
      }
   ]
}

We can get some basic information about a database with the /[database_name] endpoint like http://localhost:5984/customers:

{  
   "db_name":"customers",
   "update_seq":"9-g1AAAAFTeJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rkQGPoiQFIJlkT1idA0hdPFgdKz51CSB19WB1THjU5bEASYYGIAVUOh-_3RC1CyBq9xOj9gBE7X1i1D6AqAW5NwsA2g1vNw",
   "sizes":{  
      "file":103698,
      "external":34877,
      "active":37595
   },
   "purge_seq":0,
   "other":{  
      "data_size":34877
   },
   "doc_del_count":1,
   "doc_count":2,
   "disk_size":103698,
   "disk_format_version":6,
   "data_size":37595,
   "compact_running":false,
   "instance_start_time":"0"
}

If we try the same with a non-existent database then we get 404 Not Found with the following response body:

{
  "error": "not_found",
  "reason": "Database does not exist."
}

We can get a specific document from a database by attaching an ID to the request, e.g. http://localhost:5984/customers/0c458e911e3ff5b4e423bfe06c00133c :

{
  "_id": "0c458e911e3ff5b4e423bfe06c00133c",
  "_rev": "5-db3fe5937ed8ee9de36aaddc8ab3647e",
  "name": "New customer Inc",
  "preferred": false,
  "address": {
    "street": "New street",
    "city": "Birmingham",
    "country": "UK",
    "postal_code": 22222
  },
  "telephone": {
    "office": "34543534",
    "sales": "576545645",
    "customer_care": "456456567"
  },
  "year_joined": 2017,
  "current_status": "approved",
  "_attachments": {
    "Administrative databases created on single node CouchDB installation.PNG": {
      "content_type": "image/png",
      "revpos": 4,
      "digest": "md5-zHrwohh+oRdL29TExyrhrA==",
      "length": 33926,
      "stub": true
    }
  }
}

We can extend the above result to see the available revisions like this:

http://localhost:5984/customers/0c458e911e3ff5b4e423bfe06c00133c?revs_info=true

The revision information is presented in an array like this:

"_revs_info": [
    {
      "rev": "5-db3fe5937ed8ee9de36aaddc8ab3647e",
      "status": "available"
    },
    {
      "rev": "4-5edf1bd512b5cacb447e944c7305c3e1",
      "status": "available"
    },
    {
      "rev": "3-4eb766f3e74f5ae77a7d0d8c1797a5e8",
      "status": "available"
    },
    {
      "rev": "2-51be660bcbc93e6eec7b1d6f9b46afd0",
      "status": "deleted"
    },
    {
      "rev": "1-12a90088a7b760c892bca04efa017b94",
      "status": "available"
    }
  ]

We can then use these revision IDs to retrieve a specific revision, e.g. http://localhost:5984/customers/0c458e911e3ff5b4e423bfe06c00133c?rev=3-4eb766f3e74f5ae77a7d0d8c1797a5e8.

These are all examples of GET requests for various resources in CouchDB and the UI is also dependent on these requests. One way of finding a HTTP API endpoint is Fauxton as we’ve just seen it. There’s also a reference manual available here. This Wiki page is also a good resource. GET requests that don’t require any authentication can be directly tested in a web browser. Let’s try some of them:

Here’s an example of the _uuids response:

{  
   "uuids":[  
      "3559d9c81c785b6bfc27a34904001cf9",
      "3559d9c81c785b6bfc27a349040028e9",
      "3559d9c81c785b6bfc27a34904002b66",
      "3559d9c81c785b6bfc27a349040033aa",
      "3559d9c81c785b6bfc27a34904004181",
      "3559d9c81c785b6bfc27a34904004287",
      "3559d9c81c785b6bfc27a349040047a9",
      "3559d9c81c785b6bfc27a349040047ca",
      "3559d9c81c785b6bfc27a349040048ab",
      "3559d9c81c785b6bfc27a34904004cab"
   ]
}

For other types of requests, like PUT or POST it’s best to use a HTTP client like Postman or Fiddler. I’ll use Postman to test various HTTP requests against the CouchDB server. However, it’s really up to you to pick your favourite tool. This is what executing the UUID generation endpoint in Postman looks like:

Example GET request in Postman UI

Let’s now try some of the non-GET requests. We’ll first try and add a new configuration value:

PUT http://localhost:5984/_node/couchdb@localhost/_config/custom_category/custom_key

The URL means that we want to set the value of key “custom_key” in the category “custom_category”. The value for the key is provided in the body as a valid JSON argument. Strings must be passed within quotations:

Execute config PUT HTTP call against CouchDB from Postman

PUT in CouchDB generally means that the resource should be updated if it already exists or inserted if it doesn’t. In the above case there’s no such category or key so it will be inserted. We can check it in Fauxton:

Config value successfully inserted proof by Fauxton in CouchDB

The API responds with the previous value of the setting which is an empty string in the above example since the config resource didn’t exist before. Let’s see if we can update the custom configuration value:

Update a configuration value using the CouchDB HTTP API

Update the configuration screen in Fauxton and you’ll see the change. The API responds with “custom value” since that was the value of this configuration key before it was updated. Let’s now delete this dummy configuration:

Delete a configuration value from CouchDB via the HTTP API

The configuration is now gone.

We can check if a database exists with the following request: HEAD http://localhost:5984/customers , i.e. the database name is simply attached to the domain. CouchDB responds with 200 OK if the database exists or 404 Not Found if it doesn’t like in the case of HEAD http://localhost:5984/products .

We’ll continue in the next post with the HTTP API. We’ll concentrate more on the DB and document related operations.

You can view all posts related to data storage on this blog here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: