1.7. 核心 API¶
本文档深入探讨了 CouchDB 的细节。它展示了所有细致入微和巧妙的部分。我们向您展示最佳实践,并指导您避开常见的陷阱。
我们首先回顾上一篇文档中运行的基本操作 入门,看看幕后发生了什么。我们还将展示 Fauxton 在其用户界面背后需要做什么才能为我们提供之前看到的那些不错的功能。
本文档既是 CouchDB 核心 API 的介绍,也是参考手册。如果您不记得如何运行特定请求或为什么需要某些参数,您始终可以回到这里查找(我们可能是本文档最重的用户)。
在解释 API 的各个部分时,我们有时需要进行更深入的解释,以说明特定请求背后的原因。这是一个很好的机会,让我们告诉您 CouchDB 为什么以这种方式工作。
API 可以细分为以下部分。我们将逐一探讨它们
1.7.1. 服务器¶
这个很简单。它可以作为一项健全性检查,以查看 CouchDB 是否正在运行。它还可以充当库的安全保障,这些库需要特定版本的 CouchDB。我们再次使用 curl 工具
curl http://127.0.0.1:5984/
CouchDB 回复,非常兴奋地开始工作
{
"couchdb": "Welcome",
"version": "3.0.0",
"git_sha": "83bdcf693",
"uuid": "56f16e7c93ff4a2dc20eb6acc7000b71",
"features": [
"access-ready",
"partitioned",
"pluggable-storage-engines",
"reshard",
"scheduler"
],
"vendor": {
"name": "The Apache Software Foundation"
}
}
您将获得一个 JSON 字符串,如果将其解析为编程语言的原生对象或数据结构,您就可以访问欢迎字符串和版本信息。
这没什么用,但它很好地说明了 CouchDB 的行为方式。您发送一个 HTTP 请求,并在 HTTP 响应中收到一个 JSON 字符串作为结果。
1.7.2. 数据库¶
现在让我们做一些更有用的事情:创建数据库。严格来说,CouchDB 是一个数据库管理系统 (DMS)。这意味着它可以保存多个数据库。数据库是一个存储“相关数据”的桶。我们将在后面探讨这到底意味着什么。在实践中,术语是重叠的——人们通常将 DMS 称为“数据库”,并将 DMS 中的数据库也称为“数据库”。我们可能会遵循这种轻微的怪异之处,所以不要被它弄糊涂。总的来说,从上下文应该可以清楚地知道我们是在谈论整个 CouchDB 还是 CouchDB 中的单个数据库。
现在让我们创建一个!我们想存储我们最喜欢的音乐专辑,我们创造性地将我们的数据库命名为 albums。请注意,我们现在再次使用 -X
选项告诉 curl 发送一个 PUT 请求,而不是默认的 GET 请求
curl -X PUT http://admin:password@127.0.0.1:5984/albums
CouchDB 回复
{"ok":true}
就是这样。您创建了一个数据库,CouchDB 告诉您一切顺利。如果您尝试创建已经存在的数据库会发生什么?让我们再试一次创建该数据库
curl -X PUT http://admin:password@127.0.0.1:5984/albums
CouchDB 回复
{"error":"file_exists","reason":"The database could not be created, the file already exists."}
我们得到了一个错误。这非常方便。我们还了解了一些关于 CouchDB 工作原理的信息。CouchDB 将每个数据库存储在一个文件中。非常简单。
让我们创建另一个数据库,这次使用 curl 的 -v
(表示“详细”)选项。详细选项告诉 curl 不仅显示基本信息——HTTP 响应正文——还显示所有底层请求和响应详细信息
curl -vX PUT http://admin:password@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 (Erlang/OTP)
< 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。此头在 Web 开发中通常很有用,因为客户端实现中存在已知的错误,服务器可能希望为此准备响应。它还有助于确定用户所在的平台。此信息可用于技术和统计目的。对于 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 状态代码告诉客户端,针对其发出请求的资源已成功创建。这并不奇怪,但如果您记得我们在尝试两次创建此数据库时收到了错误消息,那么您现在知道此响应可能包含不同的响应代码。根据响应代码采取行动是一种常见的做法。例如,所有 400 Bad Request 或更大的响应代码都告诉您发生了错误。如果您想简化您的逻辑并立即处理错误,您只需检查一个 >= 400
响应代码。
< Server: CouchDB (Erlang/OTP)
Server 头用于诊断。它告诉我们我们正在与哪个 CouchDB 版本和哪个底层 Erlang 版本通信。一般来说,您可以忽略此头,但如果您需要它,最好知道它在那里。
< Date: Sun, 05 Jul 2009 22:48:28 GMT
Date 头告诉您服务器的时间。由于客户端和服务器时间不一定同步,因此此头纯粹是信息性的。您不应该在此基础上构建任何关键的应用程序逻辑!
< Content-Type: text/plain;charset=utf-8
The Content-Type header tells you which MIME type the HTTP response body is and its encoding. We already know CouchDB returns JSON strings. The appropriate Content-Type header is application/json. Why do we see text/plain? This is where pragmatism wins over purity. Sending an application/json Content-Type header will make a browser offer you the returned JSON for download instead of just displaying it. Since it is extremely useful to be able to test CouchDB from a browser, CouchDB sends a text/plain content type, so all browsers will display the JSON as text.
Note
There are some extensions that make your browser JSON-aware, but they are not installed by default. For more information, look at the popular JSONView extension, available for both Firefox and Chrome.
Do you remember the Accept request header and how it is set to */*
to express interest in any MIME type? If you send Accept: application/json
in your request, CouchDB knows that you can deal with a pure JSON response with the proper Content-Type header and will use it instead of text/plain.
< Content-Length: 12
The Content-Length header simply tells us how many bytes the response body has.
< Cache-Control: must-revalidate
This Cache-Control header tells you, or any proxy server between CouchDB and you, not to cache this response.
<
This empty line tells us we’re done with the response headers and what follows now is the response body.
{"ok":true}
We’ve seen this before.
* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0
The last two lines are curl telling us that it kept the TCP connection it opened in the beginning open for a moment, but then closed it after it received the entire response.
Throughout the documents, we’ll show more requests with the -v
option, but we’ll omit some of the headers we’ve seen here and include only those that are important for the particular request.
Creating databases is all fine, but how do we get rid of one? Easy – just change the HTTP method
> curl -vX DELETE http://admin:password@127.0.0.1:5984/albums-backup
This deletes a CouchDB database. The request will remove the file that the database contents are stored in. There is no “Are you sure?” safety net or any “Empty the trash” magic you’ve got to do to delete a database. Use this command with care. Your data will be deleted without a chance to bring it back easily if you don’t have a backup copy.
This section went knee-deep into HTTP and set the stage for discussing the rest of the core CouchDB API. Next stop: documents.
1.7.3. 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://admin:password@127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af -d '{"title":"There is Nothing Left to Lose","artist":"Foo Fighters"}'
CouchDB 回复
{"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.
Note
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 /_uuids
request
curl -X GET http://127.0.0.1:5984/_uuids
CouchDB 回复
{"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://admin:password@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 回复
{"_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.
1.7.3.1. 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 without you knowing 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://admin:password@127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af \
-d '{"title":"There is Nothing Left to Lose","artist":"Foo Fighters","year":"1997"}'
CouchDB 回复
{"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://admin:password@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-8aff9ee9d06671fa89c99d20a4b3ae"}
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 Replication and conflict model 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 documents.
Warning
The terms version and revision might sound familiar (if you are programming without version control, stop reading this guide 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. Don’t use the ``_rev`` token in CouchDB as a revision control system for your documents.
1.7.3.2. 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://admin:password@127.0.0.1:5984/albums/70b50bfa0a4b3aed1f8aff9e92dc16a0 \
-d '{"title":"Blackened Sky","artist":"Biffy Clyro","year":2002}'
Note
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.
现在,使用 -v
选项,CouchDB 的回复(只显示重要部分)如下所示
> PUT /albums/70b50bfa0a4b3aed1f8aff9e92dc16a0 HTTP/1.1
>
< HTTP/1.1 201 Created
< Location: http://127.0.0.1:5984/albums/70b50bfa0a4b3aed1f8aff9e92dc16a0
< ETag: "1-e89c99d29d06671fa0a4b3ae8aff9e"
<
{"ok":true,"id":"70b50bfa0a4b3aed1f8aff9e92dc16a0","rev":"1-e89c99d29d06671fa0a4b3ae8aff9e"}
我们正在响应头中获取 201 Created HTTP 状态码,正如我们之前在创建数据库时所见。 Location 头部提供我们新创建文档的完整 URL。 还有一个新的头部。 HTTP 中的 ETag 用于标识资源的特定版本。 在这种情况下,它标识了我们新文档的特定版本(第一个版本)。 听起来熟悉吗? 是的,从概念上讲,ETag 与 CouchDB 文档修订号相同,CouchDB 使用修订号作为 ETag 并不奇怪。 ETag 对缓存基础设施很有用。
1.7.3.3. 附件¶
CouchDB 文档可以像电子邮件一样具有附件。 附件由名称标识,并包含其 MIME 类型(或 Content-Type)以及附件包含的字节数。 附件可以是任何数据。 最容易将附件视为附加到文档的文件。 这些文件可以是文本、图像、Word 文档、音乐或电影文件。 让我们创建一个。
附件有自己的 URL,您可以在其中上传数据。 假设我们要将专辑封面添加到 6e1295ed6c29495e54cc05947f18c8af
文档(“There is Nothing Left to Lose”)中,并且假设封面位于当前目录中的 artwork.jpg 文件中
curl -vX PUT http://admin:[email protected]:5984/albums/6e1295ed6c29495e54cc05947f18c8af/artwork.jpg?rev=2-2739352689 \
--data-binary @artwork.jpg -H "Content-Type:image/jpg"
Note
--data-binary
@
选项告诉 curl 将文件的内容读入 HTTP 请求正文。 我们使用 -H
选项告诉 CouchDB 我们正在上传一个 JPEG 文件。 CouchDB 会保留此信息,并在请求此附件时发送相应的头部; 对于像这样的图像,浏览器会渲染图像,而不是提供下载数据。 这在以后会派上用场。 请注意,您需要提供要附加封面的文档的当前修订号,就像您要更新文档一样。 毕竟,附加一些数据会改变文档。
如果您现在将浏览器指向 http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af/artwork.jpg,您应该会看到您的封面图像。
如果您再次请求文档,您将看到一个新成员
curl http://admin:password@127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af
CouchDB 回复
{
"_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
是一个键值对列表,其中值是包含附件元数据的 JSON 对象。 stub=true
告诉我们此条目只是元数据。 如果我们在请求此文档时使用 ?attachments=true
HTTP 选项,我们将获得一个包含附件数据的 Base64 编码字符串。
我们将在后面探索 CouchDB 的更多功能(例如复制,这是下一个主题)时,查看更多文档请求选项。
1.7.4. 复制¶
CouchDB 复制是一种同步数据库的机制。 就像 rsync 同步本地或网络上的两个目录一样,复制同步本地或远程的两个数据库。
在一个简单的 POST 请求中,您告诉 CouchDB 复制的源和目标,CouchDB 会找出源上哪些文档和新文档修订号尚未在目标上,然后继续将缺失的文档和修订号移动过去。
我们将深入研究文档 复制简介 中的复制; 在本文档中,我们将只向您展示如何使用它。
首先,我们将创建一个目标数据库。 请注意,CouchDB 不会自动为您创建目标数据库,如果目标不存在,它将返回复制失败(源也是如此,但这种错误不容易犯)
curl -X PUT http://admin:password@127.0.0.1:5984/albums-replica
现在我们可以使用 albums-replica 数据库作为复制目标
curl -vX POST http://admin:password@127.0.0.1:5984/_replicate \
-d '{"source":"http://127.0.0.1:5984/albums","target":"http://127.0.0.1:5984/albums-replica"}' \
-H "Content-Type: application/json"
Note
从 CouchDB 2.0.0 开始,复制 source
和 target
参数都需要使用完全限定的 URL。
Note
CouchDB 支持 "create_target":true
选项,该选项放置在发布到 _replicate URL 的 JSON 中。 如果目标数据库不存在,它会隐式创建该数据库。
CouchDB 回复(这次我们格式化了输出,以便您更容易阅读)
{
"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 维护着复制的会话历史记录。 复制请求的响应包含此复制会话的历史记录条目。 还值得注意的是,复制请求将保持打开状态,直到复制关闭。 如果您有很多文档,复制所有文档需要一段时间,您将无法在所有文档复制完成后获得复制响应。 重要的是要注意,复制只复制数据库在复制开始时的状态。 因此,复制开始后进行的任何添加、修改或删除都不会被复制。
我们再次跳过细节 - 结尾处的 "ok": true
告诉我们一切顺利。 如果您现在查看 albums-replica 数据库,您应该会看到您在 albums 数据库中创建的所有文档。 很棒吧?
您刚才所做的在 CouchDB 术语中称为本地复制。 您创建了数据库的本地副本。 这对备份或保留数据的特定状态的快照以备后用很有用。 如果您正在开发应用程序,但希望能够回滚到代码和数据的稳定版本,您可能需要这样做。
还有更多类型的复制在其他情况下很有用。 我们复制请求的源和目标成员实际上是链接(就像在 HTML 中一样),到目前为止,我们只看到了相对于我们正在使用的服务器的链接(因此是本地的)。 您也可以指定远程数据库作为目标
curl -vX POST http://admin:password@127.0.0.1:5984/_replicate \
-d '{"source":"http://127.0.0.1:5984/albums","target":"http://example.org:5984/albums-replica"}' \
-H "Content-Type:application/json"
使用本地源和远程目标数据库称为推送复制。 我们正在将更改推送到远程服务器。
Note
由于我们还没有第二个 CouchDB 服务器,我们将只使用我们单个服务器的绝对地址,但您应该能够从这里推断出,您可以将任何远程服务器放在那里。
这对于与远程服务器或隔壁的伙伴共享本地更改非常有用。
您也可以使用远程源和本地目标进行拉取复制。 这对于从其他人使用的服务器获取最新更改非常有用
curl -vX POST http://admin:password@127.0.0.1:5984/_replicate \
-d '{"source":"http://example.org:5984/albums-replica","target":"http://127.0.0.1:5984/albums"}' \
-H "Content-Type:application/json"
最后,您可以运行远程复制,这主要用于管理操作
curl -vX POST http://admin:password@127.0.0.1:5984/_replicate \
-d '{"source":"http://example.org:5984/albums","target":"http://example.org:5984/albums-replica"}' \
-H"Content-Type: application/json"
Note
CouchDB 和 REST
CouchDB 以拥有 RESTful API 为荣,但这些复制请求对于训练有素的眼睛来说并不像 REST 那样。 这是怎么回事? 虽然 CouchDB 的核心数据库、文档和附件 API 是 RESTful 的,但并非 CouchDB 的所有 API 都是 RESTful 的。 复制 API 就是一个例子。 还有更多,我们将在后面的文档中看到。
为什么这里混合了 RESTful 和非 RESTful API? 开发人员是否太懒惰而没有完全 REST 化? 请记住,REST 是一种架构风格,它适合某些架构(例如 CouchDB 文档 API)。 但它不是万能的。 触发像复制这样的事件在 REST 世界中没有多大意义。 它更像是传统的远程过程调用。 这并没有错。
我们非常相信“为工作选择合适的工具”的理念,REST 并不适合所有工作。 为了支持,我们参考了 Leonard Richardson 和 Sam Ruby,他们撰写了 RESTful Web Services(O’Reilly),因为他们与我们观点一致。
1.7.5. 总结¶
这仍然不是完整的 CouchDB API,但我们详细讨论了基本内容。 我们将在以后补充空白。 现在,我们相信您已经准备好开始构建 CouchDB 应用程序了。