Skip to main content

This is my blog, more about me at marianoguerra.github.io

🦋 @marianoguerra.org 🐘 @marianoguerra@hachyderm.io 🐦 @warianoguerra

como extender couchdb

que sucede si queres hacer un redirect en couchdb?
que sucede si queres hacer un request a otro host desde js y debido al same origin policy no lo podes hacer?
[Insertar otras preguntas cuya respuesta sea lo que voy a explicar aqui]

mi primer opcion fue leventar un servercito de python en otro puerto, pero eso me complicaba porque violaba el same origin policy y tenia que hacer cosas feas con iframes.

entonces me puse a leer el codigo fuente de couchdb (no hay mucha info en otro lado sobre como hacerlo) y vi que la mayoria de los handlers son extensiones en couchdb.

Si se fijan en el archivo de configuracion, van a ver algo como


[httpd_global_handlers]
/ = {couch_httpd_misc_handlers, handle_welcome_req, >}
favicon.ico = {couch_httpd_misc_handlers, handle_favicon_req, "/usr/share/couchdb/www"}

_utils = {couch_httpd_misc_handlers, handle_utils_dir_req, "/usr/share/couchdb/www"}

[snip]


lo que hace eso es que mapea urls a handlers escritos en erlang, el primer elemento de la tupla es el modulo, el segundo es la funcion y el resto son parametros a la funcion.

mi primer experimento fue hacer un redirect para que la url de mi couchapp no quede tan fea, agregue estas linea en /etc/couchdb/local.ini (las otras se veran mas adelante):


editor = {fresita, redirect_editor}
_export = {fresita, export_document}
_style = {fresita, export_style}


y escribi un modulo que se ve asi:

-module(fresita).
-export([redirect_editor/1, export_document/1, export_style/1]).

redirect_editor(Req) ->
couch_httpd:send_redirect(Req, "/fresita/_design/fresita/index.html").

export_document(Req) ->
"/" ++ UrlPath = couch_httpd:path(Req),
[_Export, Database, InputId, Output, StyleId, Format, _FileName] = string:tokens(UrlPath, "/"),
Command = "python /var/lib/fop/export.py --type id --input " ++ InputId
++ " --output /tmp/" ++ Output ++ " --style " ++ StyleId ++ " --format "
++ Format ++ " --url http://localhost:5984/" ++ Database ++ "/",
log(UrlPath),
log(Command),
os:cmd(Command),
couch_httpd:serve_file(Req, Output ++ "." ++ Format, "/tmp/").

export_style(Req) ->
"/" ++ UrlPath = couch_httpd:path(Req),
[_Style, Database, StyleId] = string:tokens(UrlPath, "/"),
os:cmd("python /var/lib/fop/export.py --type style --style " ++
StyleId ++ " --url http://localhost:5984/" ++ Database ++ "/>/tmp/" ++
StyleId),
couch_httpd:serve_file(Req, StyleId, "/tmp/").

log(Text) ->
{ok, Device} = file:open("/tmp/fresita.log", [append]),
file:write(Device, Text ++ "\n").


lo que hace redirect es simplemente redirigir la url a otra que es mas compleja, los otros dos corren procesos externos y devuelven el contenido al browser (el primero genera pdf y rtf usando apache fop y el segundo hace un merge de algunas cosas).

con esto quiero documentar algo que seguro me voy a olvidar en el futuro y aportar mi granito de arena a couchdb para hacer cosas que se complican si solo tenes couchdb y el frontend en el browser.

para hacer andar esto compilas el archivo con erlc archivo.erl y lo pones en algun lugar donde erlang busque, yo lo puse donde estan todas las otras extensiones de couchdb (/usr/lib/couchdb/erlang/lib/couch-0.10.0/ebin/)