backend/DataBase

[CouchDB] HTTP Document API

버리야 2009. 7. 14. 10:02
반응형
CouchDB wiki에 있는 내용을 보고 정리한 내용입니다.
제가 하고싶은걸 실습한 것이기 때문에 삭제된 내용도 있습니다.


Naming/Addressing
CouchDB에 저장된 Document들은 DocID를 가진다. DocID는 유니크한 아이디. 두개의 document는 같은 database안에 같은 identifier를 가질 수 없다.

"test"라는 이름의 database안의 some_doc_id, another_doc_id, BA1F48C5418E4E68E5183D5BD1F06476 이름의 document가 있다.
http://localhost:5984/test/some_doc_id
http://localhost:5984/test/another_doc_id
http://localhost:5984/test/BA1F48C5418E4E68E5183D5BD1F06476

JSON
CouchDB document는 간단한 JSON object이다.
{
 "_id":"some_doc_id",
 "_rev":"D1C946B7",
 "Subject":"I like Plankton",
 "Author":"Rusty",
 "PostedDate":"2006-08-15T17:30:12-04:00",
 "Tags":["plankton", "baseball", "decisions"],
 "Body":"I decided today that I don't like baseball. I like plankton."
}

Working With Documents Over HTTP

document생성

buri라는 database안의 document들의 리스트를 얻을려면,
~]curl -i http://localhost:5984/buri/_all_docs

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Server: CouchDB/0.9.0 (Erlang OTP/R13B)
Etag: "EUBRVUD02OXJJT4QD3O565AWW"
Date: Sat, 04 Jul 2009 12:01:04 GMT
Content-Type: text/plain;charset=utf-8
Cache-Control: must-revalidate

{"total_rows":3,"offset":0,"rows":[
{"id":"038dac2f6d16d32cfa4f0beedd1b970f","key":"038dac2f6d16d32cfa4f0beedd1b970f","value":{"rev":"1-752793712"}},
{"id":"_design/log","key":"_design/log","value":{"rev":"1-1517763105"}},
{"id":"test_doc","key":"test_doc","value":{"rev":"1-2073410021"}}
]}

하나의 document의 정보를 알고 싶으면(기본필드(_id, _rev)외에 따로 추가한 필드가 없어서 응답받은 JSON은 이렇다.
~]curl http://localhost:5984/buri/test_doc
{"_id":"test_doc","_rev":"1-2073410021"}

Accessing Previous Revisions

특정한 revision의 document를 가져오고 싶으면,
~]curl http://localhost:5984/buri/test_doc?rev=1-2073410021
{"_id":"test_doc","_rev":"1-2073410021"}

document의 가능한 revision을 찾기 위해선,
~]curl http://localhost:5984/buri/test_doc?revs=true
{"_id":"test_doc","_rev":"1-2073410021","_revisions":{"start":1,"ids":["2073410021"]}}

document의 현재 revision을 반환하지만, _revisions라는 필드는 이용가능한 revision ID를 리스트를 갖는다.

_revisions 결과가 하나라서 확인하여 좀 허무하다면,
revision을 증가시키기위해, document에 필드를 추가한 후 다시 _revisions를 확인하기 위해 요청해보면,
~]curl http://localhost:5984/buri/test_doc?revs=true
{"_id":"test_doc","_rev":"2-3544093946","test":"test field","_revisions":{"start":2,"ids":["3544093946","2073410021"]}}

_rev는 현재 revision을 반환하고, _revisions는 revision의 history ids를 가지고 있다.


이용가능한 document revision에 대해 좀 더 많은 정보를 얻고 싶으면, revs_info 파라미터를 이용하면 된다.
JSON 결과는 _revs_info 프로퍼티를 포함한 객체의 배열을 리턴한다.

{
  "_revs_info": [
    {"rev": "123456", "status": "disk"},
    {"rev": "234567", "status": "missing"},
    {"rev": "345678", "status": "deleted"},
  ]
}

PUT
새로운 document를 생성하기 위해선, POST나 PUT operation을 이용하면 된다.
PUT은 document를 생성/수정할 수 있다.

이미 존재하는 document를 수정하기 위해선 JSON body에 _rev 프로퍼티를 포함하고 있어야 한다.
그래야, CouchDB가 edit할지를 안다. database에 document의 현재 저장된 revision이 맞지 않으면, 409 conflict error를 리턴한다.

만약 revision 번호가 database에 있는 값과 매치하면 새로 generated된 revision 번호를 client에 리턴한다.

~]curl -X PUT http://localhost:5984/buri/test_doc -d '{"_id":"test_doc","_rev":"2-3544093946","test":"update field"}'
{"ok":true,"id":"test_doc","rev":"3-2553359885"}


POST
POST는 서버에 generated된 DocID를 생성하기 위해 사용된다. PUT method대신에 사용되기도 하는데 가능한한 POST를 피하는 걸 추천.
proxy나 다른 네트워크가 종종 POST 요청을 재전송해 document 생성 중복요청을 하므로...

DELETE
~]curl -i -X DELETE http://localhost:5984/buri/test_doc?rev=3-2553359885

HTTP/1.1 200 OK
Server: CouchDB/0.9.0 (Erlang OTP/R13B)
Etag: "4-386883723"
Date: Sat, 04 Jul 2009 12:49:12 GMT
Content-Type: text/plain;charset=utf-8
Content-Length: 48
Cache-Control: must-revalidate

{"ok":true,"id":"test_doc","rev":"4-386883723"}


All Documents
database의 모든 document의 리스트를 얻기위해 _all_docs URI를 이용

~]curl http://localhost:5984/buri/_all_docs 이런식으로

wiki에 나와있는 예제로 보면~

GET somedatabase/_all_docs HTTP/1.0

HTTP/1.1 200 OK
Date: Thu, 17 Aug 2006 05:39:28 +0000GMT
Content-Type: application/json
Connection: close

{
  "total_rows": 3, "offset": 0, "rows": [
    {"id": "doc1", "key": "doc1", "value": {"rev": "4324BB"}},
    {"id": "doc2", "key": "doc2", "value": {"rev":"2441HF"}},
    {"id": "doc3", "key": "doc3", "value": {"rev":"74EC24"}}
  ]
}


revision ID와 DocID에 정렬로 모든 document의 리스트를 보여준다.
query argument에 descending=true 를 보내면 정렬이 descending으로 결과를 리턴한다.

~]curl http://localhost:5984/buri/_all_docs?descending=true 이런식으로

HTTP/1.1 200 OK
Date: Thu, 17 Aug 2006 05:39:28 +0000GMT
Content-Type: application/json
Connection: close

{
  "total_rows": 3, "offset": 0, "rows": [
    {"id": "doc3", "key": "doc3", "value": {"_rev":"74EC24"}}
    {"id": "doc2", "key": "doc2", "value": {"_rev":"2441HF"}},
    {"id": "doc1", "key": "doc1", "value": {"_rev": "4324BB"}},
  ]
}

query string 파라미터를 startkey, endkey와 limit을 주면 결과를 제한할 수 있다.

~]curl http://localhost:5984/buri/_all_docs?startkey="doc2"&limit=2 이런식으로 보내면

GET somedatabase/_all_docs?startkey="doc2"&limit=2 HTTP/1.0


HTTP/1.1 200 OK
Date: Thu, 17 Aug 2006 05:39:28 +0000GMT
Content-Type: application/json
Connection: close

{
  "total_rows": 3, "offset": 1, "rows": [
    {"id": "doc2", "key": "doc2", "value": {"_rev":"2441HF"}},
    {"id": "doc3", "key": "doc3", "value": {"_rev":"74EC24"}}
  ]
}

doc2 부터 두개의 값을 리턴받을 수 있다.

~]curl http://localhost:5984/buri/_all_docs?startkey="doc2"&endkey="doc3"

GET somedatabase/_all_docs?startkey="doc2"&endkey="doc3" HTTP/1.0

doc2와 doc3사이에 포함된 값을 리턴한다.


GET somedatabase/_all_docs?startkey="doc2"&limit=2&descending=true HTTP/1.0


HTTP/1.1 200 OK
Date: Thu, 17 Aug 2006 05:39:28 +0000GMT
Content-Type: application/json
Connection: close

{
  "total_rows": 3, "offset": 1, "rows": [
    {"id": "doc3", "key": "doc3", "value": {"_rev":"74EC24"}}
    {"id": "doc2", "key": "doc2", "value": {"_rev":"2441HF"}},
  ]
}

all_docs_by_seq

update됐거나, delete된 모든 document를 볼 수 있다.
~]curl http://localhost:5984/buri/_all_docs_by_seq
{"total_rows":3,"offset":0,"rows":[
{"id":"038dac2f6d16d32cfa4f0beedd1b970f","key":2,"value":{"rev":"1-752793712"}},
{"id":"a52617f0a61a11fa894a2ce6f62e3a7c","key":3,"value":{"rev":"2-695380571","deleted":true}},
{"id":"_design/log","key":5,"value":{"rev":"1-1517763105"}},
{"id":"test","key":6,"value":{"rev":"2-1465437068","deleted":true}},
{"id":"test_doc","key":10,"value":{"rev":"4-386883723","deleted":true}},
{"id":"test2_doc","key":11,"value":{"rev":"1-1479752545"}}
]}


Attachments

Document는 email과 값은 첨부파일을 가지고 있을 수 있다. 첨부파일을 사용하는 두가지 방법이 있는데 하나는 document에 인라인으로 기술하는 방법.
두번째 방법은 첨부파일을 위한 REST API을 이용하는 방법이 있다.

Inline Attachments

생성시 document의 _attachments attribute를 이용한다.
JSON 구조는 name, content_type, base64로 인코드된 첨부파일의 데이터를 가진다.
document가 리턴될때 첨부파일의 실제 데이터는 포함하지 않고 metadata만 반환된다. 실제 데이터는 따로 URI로 분라되어 fetch되어 있다.
document 요청시 첨부파일을 접근해야할때는 query parameter에 ?attachments=true를 포함해서 보낸다.

첨부파일이 있는 document 생성
{
  "_id":"attachment_doc",
  "_attachments":
  {
    "foo.txt":
    {
      "content_type":"text\/plain",
      "data": "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
    }
  }
}

document를 요청하면,

GET /database/attachment_doc

이렇게 응답을 얻는다.
{
  "_id":"attachment_doc",
  "_rev":1589456116,
  "_attachments":
  {
    "foo.txt":
    {
      "stub":true,
      "content_type":"text\/plain",
      "length":29
    }
  }
}

첨부파일을 요청하면
GET /database/attachment_doc/foo.txt

foo.txt파일의 내용인
This is a base64 encoded text
자동적으로 디코드되서 리턴된다.

Multiple Attachments

{
  "_id":"attachment_doc",
  "_attachments":
  {
    "foo.txt":
    {
      "content_type":"text\/plain",
      "data": "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
    },

   "bar.txt":
    {
      "content_type":"text\/plain",
      "data": "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
    }
  }
}

Standalone Attachments

CouchDB 0.9버젼에 추가되었다. 그 전 버젼에선 이용할 수 없다.

Content-Type 헤더를 이용하여 MIME type을 이용한다.

요청은 이렇게..

PUT somedatabase/document/attachment?rev=123 HTTP/1.0
Content-Length: 245
Content-Type: image/jpeg

<JPEG data>

응답은 이렇게 온다.
{"ok": true, "id": "document", "rev": "765B7D1C"}

첨부파일을 바꿀땐(수정)

PUT somedatabase/document/attachment?rev=765B7D1C HTTP/1.0
Content-Length: 245
Content-Type: image/jpeg

<JPEG data>

첨부파일을 삭제
DELETE somedatabase/document/attachment?rev=765B7D1C HTTP/1.0

ETags/Caching

CouchDB는 document 요청을 위해 ETag Header를 보낸다.

GET 요청의 예
GET /database/123182719287


응답
cache-control: no-cache,
pragma: no-cache
expires: Tue, 13 Nov 2007 23:09:50 GMT
transfer-encoding: chunked
content-type: text/plain;charset=utf-8
etag: "615790463"

POST 요청도 새롭게 추가되거나 document가 업데이트 하기 위해 ETag header를 리턴한다.





반응형