Introduction to CouchDB with .NET part 4: continuing with the CouchDB HTTP API

Introduction

In the previous post we started looking into the CouchDB HTTP Web API. The API allows us to communicate with the CouchDB server using HTTP calls. This and the ubiquitous JSON arguments make integration with CouchDB quite straightforward for all platforms that are capable to execute HTTP calls and surely any serious programming language should be equipped with web request execution. The HTTP API responds with JSON by default and that also makes for a seamless integration.

We have primarily looked at various requests that did not modify the database or the documents. In this post we’ll continue with testing the database and document modification endpoints in the API.

Database creation and deletion

Database creation happens through simply calling the API with the database name as the resource. A PUT request will create a database if it doesn’t exist, e.g. PUT http://localhost:5984/products :

Create a new database with the CouchDB HTTP API

It responds with a 201 Created and a small JSON in the response body. The Location header indicates the resource URL for the database:

Location header of database created indicates resource address

The location header is also returned when inserting a new document.

Let’s run the same request and see what happens:

Cannot create another database with the same name

As expected we cannot create another database with the same name.

Database deletion requires the same URL but the HTTP verb is DELETE:

Delete a database with the CouchDB HTTP API

We cannot supply just any database name. E.g. database names cannot include capital letters: http://localhost:5984/Cars

Invalid database name supplied to CouchDB HTTP API

That’s quite a clear message:

Only lowercase characters (a-z), digits (0-9), and any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter.

Run the PUT request again to recreate the products database before we continue.

Inserting a document in a database

Document insertion can happen in at least two ways. The first one is by way of a PUT request like above but we need to attach the document ID. Let’s try that first. Recall that the GET /_uuid endpoint returns a valid unique ID so I’ll use that to get one first: 3559d9c81c785b6bfc27a3490400be7d , but you can take one that your API instance returns. The PUT request must include a JSON body which represents the document. I’ll go with the following JSON:

{
	"name": "desk",
	"category": "office",
	"dimensions": {
		"height": 100,
		"width": 150,
		"length": 150
	},
	"colour": "brown"
}

New document inserted into CouchDB database using the PUT verb

The API responds with 201 Created and the following JSON in the response body format:

{
  "ok": true,
  "id": "3559d9c81c785b6bfc27a3490400be7d",
  "rev": "1-dffc12f57f68be3da7f1deea7948bd48"
}

The other way of inserting a document is the same as above but the HTTP verb changes to POST. Another change is that we don’t need to include the document ID anywhere in the request URL or the request body, it will be created automatically. Let’s test with POST http://localhost:5984/products and the following payload:

{
	"name": "desk",
	"category": "office",
	"dimensions": {
		"height": 100,
		"width": 150,
		"length": 150
	},
	"colour": "brown"
}

The request must also include the header Content-Type with the value application/json :

Add content type header to POST document creation in CouchDB HTTP API

We can now execute the POST request:

New document inserted into CouchDB database using the POST verb

We can still provide our own ID in the POST endpoint as well. We just need to include a JSON property called _id with the unique ID. I’ll go with the following JSON payload:

{
	"_id": "3559d9c81c785b6bfc27a349040125c2",
	"name": "bed",
	"category": "home",
	"dimensions": {
		"height": 80,
		"width": 100,
		"length": 200
	},
	"colour": "white"
}

The API will respond with the same ID:

{
  "ok": true,
  "id": "3559d9c81c785b6bfc27a349040125c2",
  "rev": "1-6ff0fff1b611e6c6be83a83b9777a444"
}

Updating an existing document

Updating a document involves both the ID and the revision number of the document that we want to update such as 1-6ff0fff1b611e6c6be83a83b9777a444 from the last example. We also need to supply the full document and not just the properties we want to update. In other words this is a document replacement. The revision number must be attached to the end of the PUT request URL with a ?rev query parameter. So taking this last example the update URL will be PUT http://localhost:5984/products/3559d9c81c785b6bfc27a349040125c2?rev=1-6ff0fff1b611e6c6be83a83b9777a444, i.e. the database name followed by the ID of the document we want to update. I want to change the colour of the product to green:

Updating a document with a revision ID in the request parameter

The API responds with a new revision number:

{
  "ok": true,
  "id": "3559d9c81c785b6bfc27a349040125c2",
  "rev": "2-1e14bd9983c4e0726be869359110654c"
}

We can also put the revision number in the JSON request as follows:

{
	"_rev": "2-1e14bd9983c4e0726be869359110654c",
	"name": "bed",
	"category": "home",
	"dimensions": {
		"height": 80,
		"width": 100,
		"length": 200
	},
	"colour": "blue"
}

…and we can omit the rev request parameter: PUT http://localhost:5984/products/3559d9c81c785b6bfc27a349040125c2. A third option is to add the revision number to the If-Match request header:

Supplying the if-match header to update a document in the CouchDB API

We can then omit the _rev property from the JSON payload:

{
	"name": "bed",
	"category": "home",
	"dimensions": {
		"height": 80,
		"width": 100,
		"length": 200
	},
	"colour": "purple"
}

So now we’re at revision 4:

{
  "ok": true,
  "id": "3559d9c81c785b6bfc27a349040125c2",
  "rev": "4-b169b423cd8a96c458b8b51b2ccb1070"
}

Deleting a document

To delete a document we have to send a DELETE request to the /dbname/documentID?rev=revisionID endpoint. E.g. to delete this last revision of the bed product the URL will be DELETE http://localhost:5984/products/3559d9c81c785b6bfc27a349040125c2?rev=4-b169b423cd8a96c458b8b51b2ccb1070 :

Delete a document via the CouchDB HTTP API

Alternatively we can send the revision number in the If-Match header like in the case of updates.

It’s interesting that we got a new revision number as a response. The reason is that this document hasn’t completely been deleted yet. Instead, it got a new JSON property called _deleted which was set to true. If we run a GET request to retrieve the document, i.e. against the URL http://localhost:5984/products/3559d9c81c785b6bfc27a349040125c2 we get the following JSON response:

{
  "error": "not_found",
  "reason": "deleted"
}

The deleted document will be kept until the database is compacted. DB compaction will also remove the document revisions except for the most recent one.

We can still get some basic information about the deleted document by running a GET request with the document and revision ID in the URL like http://localhost:5984/products/3559d9c81c785b6bfc27a349040125c2?rev=5-b1c8479dce3b432355cfd9df3a3fe546. The response will include the _deleted flag:

{
  "_id": "3559d9c81c785b6bfc27a349040125c2",
  "_rev": "5-b1c8479dce3b432355cfd9df3a3fe546",
  "_deleted": true
}

One way to undo a deletion is to first get the list of all available revisions via GET http://localhost:5984/products/3559d9c81c785b6bfc27a349040125c2?revs_info=true , i.e. /db-name/doc-id?revs_info=true. This will retrieve all the revisions of the provided document ID including the revision status:

{
  "_id": "3559d9c81c785b6bfc27a349040125c2",
  "_rev": "5-b1c8479dce3b432355cfd9df3a3fe546",
  "_revs_info": [    
    {
      "rev": "5-b1c8479dce3b432355cfd9df3a3fe546",
      "status": "deleted"
    },
    {
      "rev": "4-b169b423cd8a96c458b8b51b2ccb1070",
      "status": "available"
    },
    {
      "rev": "3-d4d0109727801ca29810c5976a910767",
      "status": "available"
    },
    {
      "rev": "2-1e14bd9983c4e0726be869359110654c",
      "status": "available"
    },
    {
      "rev": "1-6ff0fff1b611e6c6be83a83b9777a444",
      "status": "available"
    }
  ]
}

We can read the most recent revision that has NOT been deleted by analysing this document. It is 4-b169b423cd8a96c458b8b51b2ccb1070 in our case, i.e. we can read its properties by GET http://localhost:5984/products/3559d9c81c785b6bfc27a349040125c2?rev=4-b169b423cd8a96c458b8b51b2ccb1070. It returns the following document:

{
  "_id": "3559d9c81c785b6bfc27a349040125c2",
  "_rev": "4-b169b423cd8a96c458b8b51b2ccb1070",
  "name": "bed",
  "category": "home",
  "dimensions": {
    "height": 80,
    "width": 100,
    "length": 200
  },
  "colour": "purple"
}

We can then copy the JSON properties from here and insert a new document like we saw above in the document insertion demo: POST http://localhost:5984/products/ . Alternatively we can send a PUT request with the ID and revision number of the deleted document for an update operation.

We’ll continue in the next post with concurrency and data consistency.

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

Advertisements

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

One Response to Introduction to CouchDB with .NET part 4: continuing with the CouchDB HTTP API

  1. Pingback: CouchDB Weekly News, May 25, 2017 – CouchDB Blog

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 )

Google+ photo

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

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

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

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: