CouchDBオフィシャル・ドキュメントの Getting Started をLispを使ってやってみた.CouchDBはRESTfulなAPIを提供しているので,特別なドライバを使わなくてもHTTPクライアントがあればDBを操作できる.ここでは,LispのHTTPクライアント・ライブラリ Dexador と,高速なJSONエンコード/デコード・ライブラリ Jonathan を使って,CouchDBと通信する.どちらも日本を代表する若手Lisperによって書かれたライブラリだ.
(ql:quickload 'dexador)
(ql:quickload 'jonathan)
ダウンロードしたCouchDBをダブルクリックで起動し,ポート5984番にGETリクエストを発する.
> (dex:get "http://localhost:5984")
;=> "{\"couchdb\":\"Welcome\",\"version\":\"2.1.0\",\"features\":[\"scheduler\"],\"vendor\":{\"name\":\"The Apache Software Foundation\"}}
; "
; 200
; #<HASH-TABLE :TEST EQUAL :COUNT 7 {10041F28C3}>
; #<QURI.URI.HTTP:URI-HTTP http://localhost:5984>
; #<SB-SYS:FD-STREAM for "socket 127.0.0.1:52372, peer: 127.0.0.1:5984"
; {1004112FE3}>
CouchDBのルートURLにアクセスするとバージョンを取得できる.エスケープされた文字列は分かり辛いので,Jonathanを使ってJSONをS式に変換する.以下は読みやすいようにこちらでインデントした.
(jonathan:parse (dex:get "http://localhost:5984"))
;=> (:|vendor| (:|name| "The Apache Software Foundation")
; :|features| ("scheduler")
; :|version| "2.1.0"
; :|couchdb| "Welcome")
S式のリストがJSONの1つのオブジェクトか配列を表す.リストがキーワードを含む連想配列の時はJSONのオブジェクト(key/value dictionaries)を表し,S式表現にキーワードがなければJSON内では配列データである.上のS式は以下のJSONをパースした結果である.
{
"couchdb": "Welcome",
"version": "2.1.0",
"features": ["scheduler"],
"vendor": {
"name": "The Apache Software Foundation"
}
}
ここでタイプの手間を減らすためにマクロを定義する.
(defmacro couchdb (method path)
`(jonathan:parse (
,(intern (symbol-name method) :dex)
,(concatenate 'string "http://localhost:5984" path))))
引数の method
はシンボルでもキーワードでもOK.
(couchdb get "/_all_dbs") (1)
;=> nil
(couchdb put "/baseball") (2)
;=> (:|ok| T)
(couchdb get "/_all_dbs") (3)
;=> ("baseball")
1 | /_all_dbs でデータベース一覧を取得.まだデータベースを作成していないので空のJSONオブジェクトが返る.Lispでは nil となる. |
2 | put メソッドで baseball データベースを作成.成功すれば,ok キーに true が返される. |
3 | データベース一覧を取得すると baseball データベースが作成されているのが分かる. |
もう一度同じ名前のデータベースの作成を試みる.
(couchdb put "/baseball")
;=> An HTTP request to "http://localhost:5984/baseball" returned 412 precondition failed.
;
; {"error":"file_exists","reason":"The database could not be created, the file already exists."}
; [Condition of type DEXADOR.ERROR:HTTP-REQUEST-PRECONDITION-FAILED]
;
; Restarts:
; 0: [RETRY-REQUEST] Retry the same request.
; 1: [IGNORE-AND-CONTINUE] Ignore the error and continue.
; 2: [RETRY] Retry SLIME REPL evaluation request.
; 3: [*ABORT] Return to SLIME's top level.
; 4: [ABORT] abort thread (#<THREAD "new-repl-thread" RUNNING {1002AB5BA3}>)
Dexador はErrorシグナルを発しデバッガが立ち上がる.エラーメッセージを見るとHTTPがStatus Code 412(Precondition Failed)を返したことがわかる.これはリクエスト先のリソースへのアクセスが拒否されたことを示すステータス・コードだ.
Dexadorの エラー・コンディション・オブジェクトの定義 は以下の通り.
(define-condition http-request-failed (error)
((body :initarg :body
:reader response-body)
(status :initarg :status
:reader response-status)
(headers :initarg :headers
:reader response-headers)
(uri :initarg :uri
:reader request-uri)
(method :initarg :method
:reader request-method))
(:report (lambda (condition stream)
(with-slots (uri status) condition
(format stream "An HTTP request to ~S has failed (status=~D)."
(quri:render-uri uri)
status)))))
http-request-failed
クラスは全てのHTTPエラー・コンディション・オブジェクトの親クラス.body
スロットにサーバーから返されるbodyが,headers
スロットにヘッダが格納されている.アクセサーはそれぞれ response-body
と reponse-headers
.
コンディション・オブジェクトのおさらい.
(handler-case 実行式
(condition-type (condition-object) エラー処理)
まずはマクロを使わず手動接続.エラーを無視し結果のJSONだけ返すようにする.
(handler-case (jonathan:parse (dex:put "http://localhost:5984/baseball"))
(dex:http-request-failed (err)
(jonathan:parse (dex:response-body err))))
couchdb
マクロを再定義.
(defmacro couchdb (method path)
`(handler-case (jonathan:parse (,(intern (symbol-name method) :dex)
,(concatenate 'string "http://localhost:5984" path)))
(dex:http-request-failed (err)
(jonathan:parse (dex:response-body err)))))
もう一度,baseball
データベースの作成を試みる.
(couchdb put "/baseball")
;=> (:|reason| "The database could not be created, the file already exists."
; :|error| "file_exists")
次は,plankton
データベースを新規作成.
(couchdb put "/plankton")
;=> (:|ok| T)
データベース一覧を取得.
(couchdb get "/_all_dbs")
;=> ("baseball" "plankton")
plankton
データベースを削除し,データベース一覧を表示.
(couchdb delete "/plankton")
;=> (:|ok| T)
(couchdb get "/_all_dbs")
;=> ("baseball")
まとめ
Getting Startedでは以下の4つのAPIを学んだ.
-
"GET /"
CouchDBのバージョンが得られる. -
"PUT /database"
databaseの作成. -
"DELETE /database"
databaseの削除. -
"GET /__all_dbs"
データベース一覧.
公式ドキュメントはこの後,ブラウザ・インターフェースを提供するFauxtonのハンズオンに進むが,そこは飛ばし,次回は The Core API へ進みドキュメントの操作方法を始め,様々なデータベース設定APIを学ぶ.