Source

couchguide_ja / src / 04_core_api.rst

Full commit

4. コアAPI

(訳注:このファイルはfreezeされた第一版からコピーされたものなので、レビューの際には、原著に追随しているかどうかという観点は不要です)

この章では、CouchDBの大事なところを中心に、ベストプラクティスやよくある落とし穴を説明します。少し細かい内容となります。

まずは前章での基本的な操作を復習しながら、その背後で何が起きているかを見ていきましょう。また、Futonのユーザーインターフェイスの背後で何が起きているかをみれば、これまで見てきたCouchDBの素敵な特徴がみえてくることでしょう。

この章は、CouchDBのコアAPIの入門ですが、リファレンスにもなります。もし、リクエストの出し方や、そのパラメータが必要な理由を覚えられなくても、ここに戻って見直せば思い出せるでしょう(多分、私たちがこの章の一番のヘビーユーザーでしょう)。

APIを説明しようとするときに、リクエストを理解するために回り道の説明が必要になるかもしれません。しかし、これもCouchDBの動作を理解するためのよい機会となるでしょう。

APIはいくつかのセクションに分けることができます。順にみていきましょう:

  • サーバ
  • データベース
  • ドキュメント
  • レプリケーション

サーバ

これは基本となるAPIで、とてもシンプルです。CouchDBが正常に動いているかどうかのヘルスチェックに使います。特定のバージョンのCouchDBが必要なライブラリには、バージョンなどの安全性チェックにも使えるでしょう。またcurlを使います::

curl http://127.0.0.1:5984/

CouchDBは元気に返事してくれます::

{"couchdb":"Welcome","version":"0.10.1"}

JSON文字列を受け取って、あなたのプログラミング言語のネイティブオブジェクトやデータ構造に変換して、ようこそ文やバージョンを表示するのに使うことができます。

これがとても便利ということはありませんが、HTTPリクエストを送って、JSON文字列が入ったHTTPレスポンスを受け取るという、CouchDBの基本的な振る舞いが端的に現れています。

データベース

さて、もう少し実用的なことをしてみましょう。データベースを作成します。厳密には、CouchDBはデータベース管理システム(DMS)です。これは、CouchDBはデータベースを複数保持することができるということを意味します。データベースは「関連するデータ」を保持するバケツです。これが正確には何を意味するのか、ということについては後で見ていきます。実際には、この専門用語は重なりあっています。人々はしばしばDMSのことを「データベース」と言いますし、DMSの中のデータベースを「データベース」とも言います。私たちがこのような少し奇妙な言い回しに従うことがあるかも知れませんが、それによって混乱しないようにしてください。一般的には、CouchDB全体について話をしている場合や、CouchDBの中のひとつのデータベースについて話をしている場合には文脈から明らかでしょう。

さて、ひとつ作ってみましょう!私たちはお気に入りの音楽アルバムを保存したいと思います。独創的に、データベースの名前はalbumsとします。今、curlがデフォルトのGETリクエストの代わりにPUTリクエストを送信するように、-Xオプションをまた使っていることに注意してください。

curl -X PUT http://127.0.0.1:5984/albums

CouchDBは次のように返答します。

{"ok":true}

これだけです。あなたはデータベースを作成し、CouchDBはすべてがうまくいったことを知らせます。もし、既に存在するデータベースを作成しようとしたら、何が起きるでしょうか。もう一度このデータベースを作ってみましょう。

curl -X PUT http://127.0.0.1:5984/albums

CouchDBは次のように返答します。

{"error":"file_exists","reason":"The database could not be created, the file already exists."}

エラーが返ってきました。これはかなり便利です。CouchDBがどのように動作しているのかについて、少し学習します。CouchDBは各データベースをひとつのファイルに保存します。非常に単純です。このことは、将来的にいくつかの結果をもたらしますが、今のところ詳細は飛ばして、基礎となるストレージシステムは「付録F 強力なB木」で探索します。

もうひとつ、データベースを作りましょう。今度はcurlの-vオプション(「verbose」の意)を使います。この冗長オプションを使うと、curlはHTTPレスポンスの本文のような重要な情報以外の、基礎となるすべてのリクエストとレスポンスの詳細を表示します。

curl -vX PUT http://127.0.0.1:5984/albums-backup

curlは詳しく説明します。

* About to connect() to 127.0.0.1 port 5984 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 5984 (#0)

> PUT /albums-backup HTTP/1.1
> User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
> Host: 127.0.0.1:5984
> Accept: */*
>
< HTTP/1.1 201 Created
< Server: CouchDB/0.9.0 (Erlang OTP/R12B)
< Date: Sun, 05 Jul 2009 22:48:28 GMT
< Content-Type: text/plain;charset=utf-8
< Content-Length: 12
< Cache-Control: must-revalidate
<
{"ok":true}

* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0

何て長い言葉でしょう。何が起きているかを理解し、重要なことを見付けるために、一行づつ追ってみましょう。この出力を何度か見れば、あなたはより簡単に重要な部分を見付けることができるようになるでしょう。

* About to connect() to 127.0.0.1 port 5984 (#0)

これは、curlがリクエストURIで指定したCouchDBサーバーへのTCP接続を確立しようとしていることを示しています。まったく重要ではありませんが、ネットワークの問題をデバッグしているときは別です。

*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 5984 (#0)

curlがCouchDBに正常に接続したことを示しています。繰り返しますが、あなたがネットワークについての問題を見付けようとしているのでなければ、重要ではありません。

次の行は、>と<という文字で始まります。>は、その行が(実際の>を除いて)そのままの形でCouchDBに送信されたということを意味します。<はその行がCouchDBからcurlに送り返されたということを意味します。

> PUT /albums-backup HTTP/1.1

これは、HTTPリクエストを開始しています。そのメソッドはPUTで、URIは/albums-backup、そしてHTTPバージョンはHTTP/1.1です。場合によってはより単純になるHTTP/1.0もありますが、すべての実用的な理由からは、HTTP/1.1を使うべきです。

次に、いくつかのリクエストヘッダーを見ます。これらは、CouchDBへのリクエストについての追加の詳細を提供するために使われます。

> User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3

User-Agentヘッダーは、CouchDBに、どのようなクライアントソフトウェアがHTTPリクエストを送信してきたのかを知らせます。新しく学習することは何もありません。curlです。このヘッダーは、ウェブ開発で、サーバーがそのためにレスポンスを準備する必要のあるようなクライアントの実装における既知のエラーが存在するときにしばしば便利です。また、これはユーザーがどのプラットフォームを使用しているのかを明らかにするために役立ちます。この情報は技術的、統計的な理由で使用することができます。CouchDBにとっては、User-Agentヘッダーは関係がありません。

> Host: 127.0.0.1:5984

HostヘッダーはHTTP 1.1のために必要です。これは、リクエストとともに来たホスト名をサーバーに知らせます。

> Accept: */*

AcceptヘッダーはCouchDBに、curlがどんなメディアタイプでも受け取ることを知らせます。少し後に、何故これが便利なのかを見ていきます。

>

空の行は、リクエストヘッダーがここで終わりであり、残りのリクエストがサーバーに送信されたデータを含んでいることを表します。このケースでは、私たちは何もデータを送っていないので、残りのcurlの出力にはHTTPレスポンスだけが含まれています。

< HTTP/1.1 201 Created

CouchDBのHTTPレスポンスの最初の行はHTTPバージョンの情報(繰り返しになりますが、リクエストされたバージョンが処理できたことを知らせます)、HTTPステータスコード、そしてステータスコードメッセージです。異なったリクエストには異なったレスポンスコードが返されます。これらのすべてが、リクエストがサーバーにどのような影響を与えるのかをクライアント(私たちのケースではcurlです)に知らせます。また、エラーが起きた場合には、どのような種類のエラーかを知らせます。RFC 2616(HTTP 1.1の仕様)はレスポンスコードの振る舞いについて明確に定義します。CouchDBはRFCに完全に従います。

201 Createdステータスコードはクライアントに、リクエストが作成されたリソースが正常に作成されたことを知らせます。何も驚くことはありませんが、このデータベースを2回作成しようとしたとき、エラーメッセージを見たことを思い出せば、そのレスポンスは異なったレスポンスコードを含んでいたことが今は分かります。レスポンスコードに基づいたレスポンスに従うことは、一般的な慣習です。例えば、400以上のすべてのレスポンスコードは、何らかのエラーが起こったことを知らせます。もし、ロジックをショートカットし、すぐにエラーに対処したいのであれば、単に>= 400レスポンスコードをチェックすることができます。

< Server: CouchDB/0.10.1 (Erlang OTP/R13B)

Serverヘッダーは診断に有用です。これは、通信しているCouchDBのバージョンとその基礎となるErlangのバージョンを知らせます。一般的に、あなたはこのヘッダーを無視することができますが、必要なときにここにあるということを知っておくのは良いことです。

< Date: Sun, 05 Jul 2009 22:48:28 GMT

Dateヘッダーはサーバーの時間を知らせます。クライアントの時間とサーバーの時間とは同期している必要はないので、このヘッダーは純粋に情報提供です。これを基に重要なアプリケーションロジックを構築すべきではありません!

< Content-Type: text/plain;charset=utf-8

Content-TypeヘッダーはHTTPレスポンスの本文がどのMIMEタイプなのか、とそのエンコーディングを知らせます。私たちはすでにCouchDBがJSON文字列を返すことを知っています。適切なContent-Typeヘッダーはapplication/jsonです。何故text/plainになっているのでしょう?ここは現実主義が純粋性に勝利するところです。application/json Content-Typeヘッダーを送ると、ブラウザーはそれを単純に表示する代わりに返されたJSONをダウンロードさせようとするでしょう。CouchDBをブラウザーからテストするためには非常に便利なので、すべてのブラウザーがJSONをテキストとして表示するように、CouchDBはtext/plainコンテンツタイプを送信します。

ブラウザーのJSON対応にするためのブラウザー拡張もありますが、それらは標準でインストールされてはいません。

Acceptリクエストヘッダーと、任意のMIMEタイプへの関心を表現するためにそれを\*/\* -> */*に設定する方法を覚えているでしょうか。リクエストをAccept: application/jsonとして送信した場合、CouchDBはあなたが適切なContent-Typeの付いた純粋なJSONレスポンスを扱うことができると理解し、text/plainの代わりにそれを使うでしょう。

< Content-Length: 12

Content-Lengthヘッダーは単にレスポンスの本文が何バイトであるかを知らせます。

< Cache-Control: must-revalidate

このCache-Controlヘッダーは、あなたやCouchDBとあなたとの間にあるプロキシーサーバーにこのレスポンスをキャッシュしないよう指示します。

<

この空の行はレスポンスヘッダーが終了したことと、この後にレスポンスの本文が続くことを知らせます。

{"ok":true}

これは前に見ました。

* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0

最後の2行はcurlに、最初に開いたTCP接続をしばらく維持していたが、すべてのレスポンスを受け取った後でこれを閉じたということを知らせます。

この本を通して、私たちはより多くのリクエストを-vオプション付きで示しますが、ここで見たヘッダーのいくつかは省略し、特定のリクエストについて重要なもののみを含みます。

データベースの作成はすべて成功しましたが、削除はどのようにするのでしょうか。簡単です。単にHTTPメソッドを次のように変更します。

> curl -vX DELETE http://127.0.0.1:5984/albums-backup

これはCouchDBのデータベースを削除します。このリクエストはデータベースの内容が保存されているファイルを削除します。データベースを削除するとき、「本当に削除しますか」というセーフティーネットや、「ゴミ箱を空にする」のような魔法はありません。このコマンドは注意して使用してください。バックアップコピーを持っていなければ、あなたのデータは簡単に元に戻すチャンスなしに削除されるでしょう。

このセクションではHTTPについて膝の深さまで行き、コアCouchDB APIの残りを議論するための足場を組みました。次の停留所は、ドキュメントです。

Documents

Documents are CouchDB’s central data structure. The idea behind a document is, unsurprisingly, that of a real-world document—a sheet of paper such as an invoice, a recipe, or a business card. We already learned that CouchDB uses the JSON format to store documents. Let’s see how this storing works at the lowest level.

Each document in CouchDB has an ID. This ID is unique per database. You are free to choose any string to be the ID, but for best results we recommend a UUID (or GUID), i.e., a Universally (or Globally) Unique IDentifier. UUIDs are random numbers that have such a low collision probability that everybody can make thousands of UUIDs a minute for millions of years without ever creating a duplicate. This is a great way to ensure two independent people cannot create two different documents with the same ID. Why should you care what somebody else is doing? For one, that somebody else could be you at a later time or on a different computer; secondly, CouchDB replication lets you share documents with others and using UUIDs ensures that it all works. But more on that later; let’s make some documents::

curl -X PUT http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af -d '{"title":"There is Nothing Left to Lose","artist":"Foo Fighters"}'

CouchDB replies::

{"ok":true,"id":"6e1295ed6c29495e54cc05947f18c8af","rev":"1-2902191555"}

The curl command appears complex, but let’s break it down. First, -X PUT tells curl to make a PUT request. It is followed by the URL that specifies your CouchDB IP address and port. The resource part of the URL /albums/6e1295ed6c29495e54cc05947f18c8af specifies the location of a document inside our albums database. The wild collection of numbers and characters is a UUID. This UUID is your document’s ID. Finally, the -d flag tells curl to use the following string as the body for the PUT request. The string is a simple JSON structure including title and artist attributes with their respective values.

If you don’t have a UUID handy, you can ask CouchDB to give you one (in fact, that is what we did just now without showing you). Simply send a GET request to /_uuids::

curl -X GET http://127.0.0.1:5984/_uuids

CouchDB replies::

{"uuids":["6e1295ed6c29495e54cc05947f18c8af"]}

Voilá, a UUID. If you need more than one, you can pass in the ?count=10 HTTP parameter to request 10 UUIDs, or really, any number you need.

To double-check that CouchDB isn’t lying about having saved your document (it usually doesn’t), try to retrieve it by sending a GET request::

curl -X GET http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af

We hope you see a pattern here. Everything in CouchDB has an address, a URI, and you use the different HTTP methods to operate on these URIs.

CouchDB replies::

{"_id":"6e1295ed6c29495e54cc05947f18c8af","_rev":"1-2902191555","title":"There is Nothing Left to Lose","artist":"Foo Fighters"}

This looks a lot like the document you asked CouchDB to save, which is good. But you should notice that CouchDB added two fields to your JSON structure. The first is _id, which holds the UUID we asked CouchDB to save our document under. We always know the ID of a document if it is included, which is very convenient.

The second field is _rev. It stands for revision.

Revisions

If you want to change a document in CouchDB, you don’t tell it to go and find a field in a specific document and insert a new value. Instead, you load the full document out of CouchDB, make your changes in the JSON structure (or object, when you are doing actual programming), and save the entire new revision (or version) of that document back into CouchDB. Each revision is identified by a new _rev value.

If you want to update or delete a document, CouchDB expects you to include the _rev field of the revision you wish to change. When CouchDB accepts the change, it will generate a new revision number. This mechanism ensures that, in case somebody else made a change unbeknownst to you before you got to request the document update, CouchDB will not accept your update because you are likely to overwrite data you didn’t know existed. Or simplified: whoever saves a change to a document first, wins. Let’s see what happens if we don’t provide a _rev field (which is equivalent to providing a outdated value)::

curl -X PUT http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af -d '{"title":"There is Nothing Left to Lose","artist":"Foo Fighters","year":"1997"}'

CouchDB replies::

{"error":"conflict","reason":"Document update conflict."}

If you see this, add the latest revision number of your document to the JSON structure::

curl -X PUT http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af -d '{"_rev":"1-2902191555","title":"There is Nothing Left to Lose", "artist":"Foo Fighters","year":"1997"}'

Now you see why it was handy that CouchDB returned that _rev when we made the initial request. CouchDB replies::

{"ok":true,"id":"6e1295ed6c29495e54cc05947f18c8af","rev":"2-2739352689"}

CouchDB accepted your write and also generated a new revision number. The revision number is the md5 hash of the transport representation of a document with an N- prefix denoting the number of times a document got updated. This is useful for replication. See Chapter 17, Conflict Management for more information.

There are multiple reasons why CouchDB uses this revision system, which is also called Multi-Version Concurrency Control (MVCC). They all work hand-in-hand, and this is a good opportunity to explain some of them.

One of the aspects of the HTTP protocol that CouchDB uses is that it is stateless. What does that mean? When talking to CouchDB you need to make requests. Making a request includes opening a network connection to CouchDB, exchanging bytes, and closing the connection. This is done every time you make a request. Other protocols allow you to open a connection, exchange bytes, keep the connection open, exchange more bytes later—maybe depending on the bytes you exchanged at the beginning—and eventually close the connection. Holding a connection open for later use requires the server to do extra work. One common pattern is that for the lifetime of a connection, the client has a consistent and static view of the data on the server. Managing huge amounts of parallel connections is a significant amount of work. HTTP connections are usually short-lived, and making the same guarantees is a lot easier. As a result, CouchDB can handle many more concurrent connections.

Another reason CouchDB uses MVCC is that this model is simpler conceptually and, as a consequence, easier to program. CouchDB uses less code to make this work, and less code is always good because the ratio of defects per lines of code is static.

The revision system also has positive effects on replication and storage mechanisms, but we’ll explore these later in the book.

The terms version and revision might sound familiar (if you are programming without version control, drop this book right now and start learning one of the popular systems). Using new versions for document changes works a lot like version control, but there’s an important difference: CouchDB does not guarantee that older versions are kept around.

Documents in Detail

Now let’s have a closer look at our document creation requests with the curl -v flag that was helpful when we explored the database API earlier. This is also a good opportunity to create more documents that we can use in later examples.

We’ll add some more of our favorite music albums. Get a fresh UUID from the /_uuids resource. If you don’t remember how that works, you can look it up a few pages back.:

curl -vX PUT http://127.0.0.1:5984/albums/70b50bfa0a4b3aed1f8aff9e92dc16a0 -d '{"title":"Blackened Sky","artist":"Biffy Clyro","year":2002}'

By the way, if you happen to know more information about your favorite albums, don’t hesitate to add more properties. And don’t worry about not knowing all the information for all the albums. CouchDB’s schema-less documents can contain whatever you know. After all, you should relax and not worry about data.

Now with the -v option, CouchDB’s reply (with only the important bits shown) looks like this::

> PUT /albums/70b50bfa0a4b3aed1f8aff9e92dc16a0 HTTP/1.1
>
< HTTP/1.1 201 Created
< Location: http://127.0.0.1:5984/albums/70b50bfa0a4b3aed1f8aff9e92dc16a0
< Etag: "1-2248288203"
<
{"ok":true,"id":"70b50bfa0a4b3aed1f8aff9e92dc16a0","rev":"1-2248288203"}

We’re getting back the 201 Created HTTP status code in the response headers, as we saw earlier when we created a database. The Location header gives us a full URL to our newly created document. And there’s a new header. An Etag in HTTP-speak identifies a specific version of a resource. In this case, it identifies a specific version (the first one) of our new document. Sound familiar? Yes, conceptually, an Etag is the same as a CouchDB document revision number, and it shouldn’t come as a surprise that CouchDB uses revision numbers for Etags. Etags are useful for caching infrastructures. We’ll learn how to use them in Chapter 8, Show Functions.

Attachments

CouchDB documents can have attachments just like an email message can have attachments. An attachment is identified by a name and includes its MIME type (or Content-Type) and the number of bytes the attachment contains. Attachments can be any data. It is easiest to think about attachments as files attached to a document. These files can be text, images, Word documents, music, or movie files. Let’s make one.

Attachments get their own URL where you can upload data. Say we want to add the album artwork to the 6e1295ed6c29495e54cc05947f18c8af document (“There is Nothing Left to Lose”), and let’s also say the artwork is in a file artwork.jpg in the current directory::

> curl -vX PUT http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af/ artwork.jpg?rev=2-2739352689 --data-binary @artwork.jpg -H "Content-Type: image/jpg"

The -d@ option tells curl to read a file’s contents into the HTTP request body. We’re using the -H option to tell CouchDB that we’re uploading a JPEG file. CouchDB will keep this information around and will send the appropriate header when requesting this attachment; in case of an image like this, a browser will render the image instead of offering you the data for download. This will come in handy later. Note that you need to provide the current revision number of the document you’re attaching the artwork to, just as if you would update the document. Because, after all, attaching some data is changing the document.

You should now see your artwork image if you point your browser to http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af/artwork.jpg.

If you request the document again, you’ll see a new member::

curl http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af

CouchDB replies::

{"_id":"6e1295ed6c29495e54cc05947f18c8af","_rev":"3-131533518","title": "There is Nothing Left to Lose","artist":"Foo Fighters","year":"1997","_attachments":{"artwork.jpg":{"stub":true,"content_type":"image/jpg","length":52450}}}

_attachments is a list of keys and values where the values are JSON objects containing the attachment metadata. stub=true tells us that this entry is just the metadata. If we use the ?attachments=true HTTP option when requesting this document, we’d get a Base64-encoded string containing the attachment data.

We’ll have a look at more document request options later as we explore more features of CouchDB, such as replication, which is the next topic.

Replication

CouchDB replication is a mechanism to synchronize databases. Much like rsync synchronizes two directories locally or over a network, replication synchronizes two databases locally or remotely.

In a simple POST request, you tell CouchDB the source and the target of a replication and CouchDB will figure out which documents and new document revisions are on source that are not yet on target, and will proceed to move the missing documents and revisions over.

We’ll take an in-depth look at replication later in the book; in this chapter, we’ll just show you how to use it.

First, we’ll create a target database. Note that CouchDB won’t automatically create a target database for you, and will return a replication failure if the target doesn’t exist (likewise for the source, but that mistake isn’t as easy to make)::

curl -X PUT http://127.0.0.1:5984/albums-replica

Now we can use the database albums-replica as a replication target::

curl -vX POST http://127.0.0.1:5984/_replicate -d '{"source":"albums","target":"albums-replica"}'

As of version 0.11, CouchDB supports the option "create_target":true placed in the JSON POSTed to the _replicate URL. It implicitly creates the target database if it doesn’t exist.

CouchDB replies (this time we formatted the output so you can read it more easily)::

{
"history": [
  {
    "start_last_seq": 0,
    "missing_found": 2,
    "docs_read": 2,
    "end_last_seq": 5,
    "missing_checked": 2,
    "docs_written": 2,
    "doc_write_failures": 0,
    "end_time": "Sat, 11 Jul 2009 17:36:21 GMT",
    "start_time": "Sat, 11 Jul 2009 17:36:20 GMT"
  }
],
"source_last_seq": 5,
"session_id": "924e75e914392343de89c99d29d06671",
"ok": true
}

CouchDB maintains a session history of replications. The response for a replication request contains the history entry for this replication session. It is also worth noting that the request for replication will stay open until replication closes. If you have a lot of documents, it’ll take a while until they are all replicated and you won’t get back the replication response until all documents are replicated. It is important to note that replication replicates the database only as it was at the point in time when replication was started. So, any additions, modifications, or deletions subsequent to the start of replication will not be replicated.

We’ll punt on the details again—the "ok": true at the end tells us all went well. If you now have a look at the albums-replica database, you should see all the documents that you created in the albums database. Neat, eh?

What you just did is called local replication in CouchDB terms. You created a local copy of a database. This is useful for backups or to keep snapshots of a specific state of your data around for later. You might want to do this if you are developing your applications but want to be able to roll back to a stable version of your code and data.

There are more types of replication useful in other situations. The source and target members of our replication request are actually links (like in HTML) and so far we’ve seen links relative to the server we’re working on (hence local). You can also specify a remote database as the target::

curl -vX POST http://127.0.0.1:5984/_replicate -d '{"source":"albums","target":"http://127.0.0.1:5984/albums-replica"}'

Using a local source and a remote target database is called push replication. We’re pushing changes to a remote server.

Since we don’t have a second CouchDB server around just yet, we’ll just use the absolute address of our single server, but you should be able to infer from this that you can put any remote server in there.

This is great for sharing local changes with remote servers or buddies next door.

You can also use a remote source and a local target to do a pull replication. This is great for getting the latest changes from a server that is used by others::

curl -vX POST http://127.0.0.1:5984/_replicate -d '{"source":"http://127.0.0.1:5984/albums-replica","target":"albums"}'

Finally, you can run remote replication, which is mostly useful for management operations::

curl -vX POST http://127.0.0.1:5984/_replicate -d '{"source":"http://127.0.0.1:5984/albums","target":"http://127.0.0.1:5984/albums-replica"}'

CouchDB and REST

CouchDB prides itself on having a RESTful API, but these replication requests don’t look very RESTy to the trained eye. What’s up with that? While CouchDB’s core database, document, and attachment API are RESTful, not all of CouchDB’s API is. The replication API is one example. There are more, as we’ll see later in the book.

Why are there RESTful and non-RESTful APIs mixed up here? Have the developers been too lazy to go REST all the way? Remember, REST is an architectural style that lends itself to certain architectures (such as the CouchDB document API). But it is not a one-size-fits-all. Triggering an event like replication does not make a whole lot of sense in the REST world. It is more like a traditional remote procedure call. And there is nothing wrong with this.

We very much believe in the “use the right tool for the job” philosophy, and REST does not fit every job. For support, we refer to Leonard Richardson and Sam Ruby who wrote RESTful Web Services (O’Reilly), as they share our view.

Wrapping Up

This is still not the full CouchDB API, but we discussed the essentials in great detail. We’re going to fill in the blanks as we go. For now, we believe you’re ready to start building CouchDB applications.