Skip to content

CouchDB - HTTP API

CouchDB is an API-first database. All interactions, from creating databases to querying complex data, happen over its RESTful HTTP API. This design makes CouchDB incredibly versatile, allowing any language or tool that can make an HTTP request to become a CouchDB client. Data is almost always sent and received as JSON (JavaScript Object Notation).

You’ll use standard HTTP methods to communicate your intent to the database. Think of them as verbs for managing your data:

  • GET: Retrieve a resource. This could be information about the server, a database, a specific document, or the results of a query.
  • HEAD: Same as GET, but retrieves only the HTTP headers of the response, not the body. Useful for checking a resource’s status or revision number (_rev) without downloading the entire payload.
  • POST: Create a new resource without specifying its ID (letting CouchDB generate one) or perform special operations, such as querying with the Mango _find endpoint or batch operations with _bulk_docs.
  • PUT: Create or update a resource at a specific, client-named URL. This is used to create named databases and create or update documents with a known _id.
  • DELETE: Remove a resource, such as a document or a database. This operation is permanent.
  • COPY: A special, non-standard method used by CouchDB to duplicate documents. It’s a convenient shortcut for a GET followed by a PUT.

While many headers are available, two are critical for most interactions:

  • Content-Type: When you send data to CouchDB (with PUT or POST), you must specify what format it’s in. For nearly all database operations, this will be application/json.
  • Accept: Tells CouchDB what data format(s) your client prefers for the response. While often optional, it’s a best practice to specify application/json to ensure you get predictable JSON output.

The server’s response headers provide important metadata about the result of your request:

  • Content-Type: Specifies the MIME type of the response body, usually application/json or text/plain; charset=utf-8.
  • Content-Length: The size of the response body in bytes.
  • Etag: For document and view responses, this header contains the document’s revision value (e.g., "1-a954784578bca65545a1989467262913"). This is the same as the _rev field in the JSON body and is crucial for caching and conflict management.
  • Cache-Control: Provides caching directives. CouchDB often returns must-revalidate, indicating that caches should confirm the resource is still current before using a cached copy.

Understanding status codes is key to building robust applications. Here are the most common ones you’ll encounter:

CodeMeaning & Context
200 OKThe request was successful. Used for successful GET and PUT updates.
201 CreatedA resource (database or document) was successfully created. Used for successful PUT creations and some POSTs.
202 AcceptedThe request was accepted for background processing, like database compaction.
304 Not ModifiedUsed with conditional requests (e.g., If-None-Match header with an Etag) to indicate the resource has not changed.
400 Bad RequestThe request was malformed. The JSON body might be invalid, or a query parameter is incorrect.
401 UnauthorizedAuthentication is required, but credentials were not provided or were incorrect.
404 Not FoundThe requested resource (database, document, view) does not exist.
409 ConflictA document update could not be completed. This almost always means the _rev you supplied is not the latest one. This is a core feature, not an error to be feared!
500 Internal Server ErrorSomething went wrong on the server. Check the CouchDB logs for details.

Modern Querying: The _find Endpoint (Mango)

Section titled “Modern Querying: The _find Endpoint (Mango)”

While traditional MapReduce views are powerful, modern CouchDB (2.0+) offers the Mango query engine, which provides a simple, declarative JSON-based way to query your data. It’s often easier and more intuitive for common use cases.

To use it, you POST a selector object to the /_find endpoint of your database. You first need to create an index on the fields you want to query.

First, create an index on the ‘role’ field:

POST /users/_index
Content-Type: application/json
{
"index": {
"fields": ["role"]
},
"name": "role-index",
"type": "json"
}

Then, query for all users with the role ‘admin’:

POST /users/_find
Content-Type: application/json
{
"selector": {
"role": "admin"
}
}