El Libro Para Principiantes en Node.js

78
Principiantes en Node.js Un tutorial de Node.js por: Manuel Kiessling & Herman A. Junge Sobre el Tutorial El objetivo de este documento es ayudarte a empezar con el desarrollo de aplicaciones para Node.js, enseñándote todo lo que necesites saber acerca de JavaScript "avanzado" sobre la marcha. Este tutorial va mucho más allá del típico manual "Hola Mundo". Status Estás leyendo la versión final de este libro, es decir, las actualizaciones solo serán hechas para corregir errores o para reflejar cambiar en nuevas versiones de Node.js.

description

El objetivo de este documento es ayudarte a empezar con el desarrollo de aplicaciones para Node.js, enseñándote todo lo que necesites saber acerca de JavaScript "avanzado" sobre la marcha. Este tutorial va mucho más allá del típico manual "Hola Mundo".

Transcript of El Libro Para Principiantes en Node.js

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font- 1/78

    Principiantes enNode.js

    UntutorialdeNode.jspor:ManuelKiessling&HermanA.Junge

    Sobre el TutorialEl objetivo de este documento es ayudarte aempezar con el desarrollo de aplicaciones paraNode.js, ensendote todo lo que necesites saberacerca de JavaScript "avanzado" sobre la marcha.Este tutorial va mucho ms all del tpico manual"Hola Mundo".

    StatusEsts leyendo la versin final de este libro, es decir,las actualizaciones solo sern hechas para corregirerrores o para reflejar cambiar en nuevas versionesde Node.js.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font- 2/78

    Las muestras de cdigo de este libro estn probadaspara funcionar con la versin 0.6.11 de Node.js.

    Audiencia ObjetivoEste documento probablemente ser mejorentendido por los lectores que tengan un trasfondosimilar al mo: Programadores experimentados enal menos un lenguaje orientado al objeto, comoRuby, Python, PHP o Java; poca experiencia conJavaScript, y ninguna experiencia en Node.js.

    El que este documento est orientado adesarrolladores que ya tienen experiencia con otroslenguajes de programacin significa que no vamos acubrir temas realmente bsicos como tipos de datos,variables, estructuras de control y similares. Debessaber acerca de estos tpicos para entender estedocumento.

    Sin embargo, dado que las funciones y objetos enJavaScript son diferentes de sus contrapartes en la

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font- 3/78

    mayora de los lenguajes, estos sern explicados conms detalle.

    Estructura de este documentoAl Trmino de este documento, habrs creado unaaplicacin Web completa, que permita a losusuarios de sta el ver pginas web y subir archivos.

    La cual, por supuesto, no va ser nada como la"aplicacin que va a cambiar el mundo", no obstanteeso, nosotros haremos la milla extra y no vamosslo a codificar una aplicacin lo "suficientementesimple" para hacer estos casos de uso posible, sinoque crearemos un framework sencillo, perocompleto, a fin de poder separar los distintosaspectos de nuestra aplicacin. Vers lo que estosignifica en poco tiempo.

    Empezaremos por mirar cmo el desarrollo enJavaScript en Node.js es diferente del desarrollo enJavaScript en un browser.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font- 4/78

    Luego, nos mantendremos con la vieja tradicin deescribir una aplicacin "Hola Mundo", la cual es laaplicacin ms bsica de Node.js que "hace" algo.

    Enseguida, discutiremos que tipo de "aplicacin delmundo real" queremos construir, disectaremos lasdiferentes partes que necesitan ser implementadaspara ensamblar esta aplicacin, y empezaremostrabajando en cada una de estas partes paso a paso.

    Tal y cual lo prometido, aprenderemos sobre lamarcha acerca de algunos de los muchos conceptosavanzados de JavaScript, como hacer uso de ellos, yver el porqu tiene sentido el hacer uso de estosconceptos en vez de los que ya conocemos por otroslenguajes de programacin.

    Tabla de Contenidos

    JavaScript y Node.js

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font- 5/78

    JavaScript y TAntes que hablemos de toda la parte tcnica,tommonos un minuto y hablemos acerca de ti y turelacin con JavaScript. Este captulo est aqu parapermitirte estimar si tiene sentido el que sigas o noleyendo este documento.

    Si eres como yo, empezaste con el "desarrollo"HTML hace bastante tiempo, escribiendodocumentos HTML. Te encontraste en el caminocon esta cosa simptica llamada JavaScript, perosolo la usabas en una forma muy bsica, agregandointeractividad a tus pginas de cuando en cuando.

    Lo que realmente quisiste era "la cosa real", querassaber cmo construir sitios web complejos -Aprendiste un lenguaje de programacin comoPHP, Ruby, Java, y empezaste a escribir cdigo"backend".

    No obstante, mantuviste un ojo en JavaScript, y tediste cuenta que con la introduccin de jQuery,

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font- 6/78

    Prototype y otros, las cosas se fueron poniendo msavanzadas en las Tierras de JavaScript, y que estelenguaje era realmente ms que hacerun window.open().

    Sin embargo, esto era todo cosa delfrontend, yaunque era agradable contar con jQuery a tudisposicin en cualquier momento que te sintierascon nimo de sazonar una pgina web, al final delda, lo que eras a lo ms, era un usuario deJavaScript, pero no, un desarrollador de JavaScript.

    Y entonces lleg Node.js. JavaScript en el servidor,Qu hay con eso?

    Decidiste que era ya tiempo de revisar el nuevoJavaScript. Pero espera: Escribir aplicacionesNode.js es una cosa; Entender el porqu ellasnecesitan ser escritas en la manera que lo sonsignifica entender JavaScript! Y esta vez es en serio.

    Y aqu est el problema: Ya que JavaScript

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font- 7/78

    realmente vive dos, o tal vez tres vidas (El pequeoayudante DHTML de mediados de los 90's, las cosasms serias tales como jQuery y similares, y ahora, ellado del servidor), no es tan fcil encontrarinformacin que te ayude a aprender JavaScript dela "manera correcta", de forma de poder escribiraplicaciones de Node.js en una apariencia que tehaga sentir que no slo ests usando JavaScript,sino que tambin estn desarrollando con l.

    Porque ah est el asunto: Ya eres un desarrolladorexperimentado, y no quieres aprender una nuevatcnica simplemente metiendo cdigo aqu y allmal-aprovechndolo; Quieres estar seguro que teests enfocando en un ngulo correcto.

    Hay, por supuesto, excelente documentacin afuera.Pero la documentacin por s sola no es suficiente.Lo que se necesita es una gua.

    Mi objetivo es proveerte esta gua.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font- 8/78

    Una AdvertenciaHay algunas personas realmente excelente enJavaScript. No soy una de ellas.

    Yo soy realmente el tipo del que te he hablado en losprrafos previos. S un par de cosas acerca dedesarrollar aplicaciones backend, pero an soynuevo al JavaScript "real" y an ms nuevo aNode.js. He aprendido solo recientemente alguno delos aspectos avanzados de JavaScript. No soyexperimentado.

    Por lo que este no es un libro "desde novicio hastaexperto". Este es ms bien un libro "desde novicio anovicio avanzado".

    Si no fallo, entonces este ser el tipo de documentoque deseo hubiese tenido cuando empec conNode.js.

    JavaScript del Lado del

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font- 9/78

    ServidorLas primeras encarnaciones de JavaScript vivan enlos browsers. Pero esto es slo el contexto. Define loque puedes hacer con el lenguaje, pero no dicemucho acerca de lo que el lenguaje mismo puedehacer. JavaScript es un lenguaje "completo": Lopuedes usar en muchos contextos y alcanzar conste, todo lo que puedes alcanzar con cualquier otrolenguaje "completo".

    Node.js realmente es slo otro contexto: te permitecorrer cdigo JavaScript en el backend, fuera delbrowser.

    Para ejecutar el cdigo JavaScript que tu pretendescorrer en el backend, este necesita ser interpretadoy, bueno, ejecutado, Esto es lo que Node.js realiza,haciendo uso de la Maquina Virtual V8 de Google, elmismo entorno de ejecucin para JavaScript queGoogle Chrome utiliza.

    Adems, Node.js viene con muchos mdulos tiles,

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 10/78

    de manera que no tienes que escribir todo de cero,como por ejemplo, algo que ponga un string a laconsola.

    Entonces, Node.js es en realidad dos cosas: unentorno de ejecucin y una librera.

    Para hacer uso de stas (la librera y el entorno),necesitas instalar Node.js. En lugar de repetir elproceso aqu, te ruego visitar las instruccionesoficiales de instalacin. Por favor vuelve una vez quetengas tu versin de Node.js corriendo.

    "Hola Mundo"Ok. Saltemos entonces al agua fra y escribamosnuestra primera aplicacin Node.js: "Hola Mundo".

    Abre tu editor favorito y crea un archivollamado holamundo.js. Nosotros queremos escribir"Hola Mundo" a STDOUT, y aqu est el cdigonecesario para hacer esto:

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 11/78

    console.log("Hola Mundo");

    Graba el archivo, y ejectalo a travs de Node.js:

    node holamundo.js

    Este debera retornar Hola Mundoen tu monitor.

    Ok, esto es aburrido, de acuerdo? As queescribamos alguna cosa real.

    Una Aplicacin WebCompleta con Node.js

    Los casos de UsoMantengmoslo simple, pero realista:

    El Usuario debera ser capaz de ocupar nuestraaplicacin con un browser.El Usuario debera ver una pgina de bienvenidacuando solicita http://dominio/inicio, la cualdespliega un formulario de sbida.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 12/78

    Eligiendo un archivo de imagen para subir yenviando el formulario, la imagen debera sersubida a http://dominio/subir, donde esdesplegada una vez que la sbida este finalizada.

    Muy bien. Ahora, tu puedes ser capaz de alcanzareste objetivo googleando y programando lo que sea,pero eso no es lo que queremos hacer aqu.

    Ms que eso, no queremos escribir simplemente elcdigo ms bsico posible para alcanzar esteobjetivo, no importa lo elegante y correcto quepueda ser este cdigo. Nosotros agregaremosintencionalmente ms abstraccin de la necesariade manera de poder tener una idea de lo que esconstruir aplicaciones ms complejas de Node.js.

    La Pila de AplicacionesHagamos un desglose a nuestra aplicacin. Qupartes necesitan ser implementadas para podersatisfacer nuestros casos de uso?

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 13/78

    Queremos servir pginas web, de manera quenecesitamos unServidor HTTP.Nuestro servidor necesitar responderdirectamente peticiones (requests), dependiendode qu URL sea pedida en este requerimiento, esque necesitaremos algn tipo deenrutador(router) de manera de mapear los peticiones alos handlers (manejadores) de stos.Para satisfacer a los peticiones que llegaron alservidor y han sido ruteados usando elenrutador, necesitaremos de hecho handlers(manejadores) de peticionesEl Enrutador probablemente debera tratarcualquier informacin POST que llegue y drselaa los handlers de peticiones en una formaconveniente, luegonecesitaremos manipulacin de data depeticinNosotros no solo queremos manejar peticionesde URLs, sino que tambin queremos desplegarcontenido cuando estas URLs sean pedidas, loque significa que necesitamos algn tipode lgica en las vistas a ser utilizada por loshandlers de peticiones, de manera de poderenviar contenido al browser del Usuario.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 14/78

    Por ltimo, pero no menos importante, elUsuario ser capaz de subir imgenes, as quenecesitaremos algn tipo demanipulacin desubidasquien se har cargo de los detalles.

    Pensemos un momento acerca de comoconstruiramos esta pila de aplicaciones con PHP.No es exactamente un secreto que la configuracintpica sera un Apache HTTP server con mod_php5instalado. Lo que, a su vez, significa que el tema "Necesitamosser capaces de servir pginas web y recibirpeticiones HTTP" ni siquiera sucede dentro de PHPmismo.

    Bueno, con Node.js, las cosas son un poco distintas.Porque con Node.js, no solo implementamosnuestra aplicacin, nosotros tambinimplementamos todo el servidor HTTP completo.De hecho, nuestra aplicacin web y su servidor webson bsicamente lo mismo.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 15/78

    Esto puede sonar como mucho trabajo, peroveremos en un momento que con Node.js, no lo es.

    Empecemos por el principio e implementemos laprimera parte de nuestra pila, el servidor HTTP..

    Construyendo la Pila deAplicaciones

    Un Servidor HTTP BsicoCuando llegu al punto donde quera empezar conmi primera aplicacin Node.js "real", me preguntno solo como la iba a programar, sino que tambin,como organizar mi cdigo. Necesitar tenerlo todo en un archivo? Muchostutoriales en la Web que te ensean cmo escribirun servidor HTTP bsico en Node.js tienen toda lalgica en un solo lugar. Qu pasa si yo quieroasegurarme que mi cdigo se mantenga leble amedida que le vaya agregando ms cosas?

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 16/78

    Resulta, que es relativamente fcil de mantener losdistintos aspectos de tu cdigo separados,ponindolos en mdulos.

    Esto te permite tener un archivomain limpio, en elcual ejecutas Node.js, y mdulos limpios quepueden ser utilizados por el archivomain entremuchos otros.

    As que vamos a crear un archivomain el cualusaremos para iniciar nuestra aplicacin, y unarchivo de mdulo dnde residir el cdigo denuestro servidor HTTP.

    Mi impresin es que es ms o menos un estndarnombrar a tu archivo principal como index.js. Tienesentido tambin que pongamos nuestro mdulo deservidor en un archivo llamadoserver.js.

    Empecemos con el mdulo del servidor. Crea elarchivo server.js en el directorio raz de tu proyecto,y llnalo con el cdigo siguiente:

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 17/78

    var http = require("http");

    http.createServer(function(request, response) { response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Mundo"); response.end();}).listen(8888);

    Eso es! Acabas de escribir un servidor HTTP activo.Probmoslo ejecutndolo y testendolo. Primeroejecuta tu script con Node.js:

    node server.js

    Ahora, abre tu browser y apntaloahttp://localhost:8888/. Esto debera desplegaruna pgina web que diga "Hola Mundo".

    Interesante, no? Qu tal si hablamos de que estpasando aqu y dejamos la pregunta de 'cmoorganizar nuestro proyecto' para despus? Prometoque volveremos a esto.

    Analizando nuestro servidorHTTP

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 18/78

    Bueno, entonces, analicemos que est pasando aqu.

    La primera lnea require, requiere almdulo http que viene incluido con Node.js y lohace accesible a travs de la variable http.

    Luego llamamos a una de las funciones que elmdulo http ofrece:createServer. Esta funcinretorna un objeto, y este objeto tiene un mtodollamado listen (escucha), y toma un valor numricoque indica el nmero de puerto en que nuestroservidor HTTP va a escuchar.

    Por favor ignora por un segundo a la definicin defuncin que sigue a la llave de aperturadehttp.createServer.

    Nosotros podramos haber escrito el cdigo queinicia a nuestro servidor y lo hace escuchar al puerto8888 de la siguiente manera:

    var http = require("http");var server = http.createServer();server.listen(8888);

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 19/78

    Esto hubiese iniciado al servidor HTTP en el puerto8888 y no hubiese hecho nada ms (ni siquierarespondido alguna peticin entrante).

    La parte realmente interesante (y rara, si tutrasfondo es en un lenguaje ms conservador, comoPHP) es que la definicin de funcin est ah mismodonde uno esperara el primer parmetro de lallamada acreateServer().

    Resulta que, este definicin de funcin ES el primer(y nico) parmetro que le vamos a dar a la llamadaa createServer(). Ya que en JavaScript, las funcionespueden ser pasadas de un lado a otro comocualquier otro valor.

    Pasando Funciones de un Ladoa OtroPuedes, por ejemplo, hacer algo como esto:

    function decir(palabra) { console.log(palabra);}

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 20/78

    function ejecutar(algunaFuncion, valor) { algunaFuncion(valor);}

    ejecutar(decir, "Hola");

    Lee esto cuidadosamente! Lo que estamos haciendoaqu es, nosotros pasamos la funcin decir() comoel primer parmetro de la funcinejecutar. No elvalor de retorno dedecir, sino que decir() misma!

    Entonces, decir se convierte en la variablelocal algunaFuncion dentro de ejecutar, y ejecutarpuede llamar a la funcin en esta variableusandoalgunaFuncion() (agregando llaves).

    Por supuesto, dado que decir toma unparmetro, ejecutar puede pasar tal parmetrocuando llama aalgunaFuncion.

    Nosotros podemos, tal como lo hicimos, pasar unafuncin por su nombre como parmetro a otrafuncin. Pero no estamos obligados a tener quedefinir la funcin primero y luego pasarla. Podemostambin definir y pasar la funcin como un

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 21/78

    parmetro a otra funcin todo al mismo tiempo:

    function ejecutar(algunaFuncion, valor) { algunaFuncion(valor);}

    ejecutar(function(palabra){ console.log(palabra) }, "Hola");

    (N.del T.: function es una palabra clave deJavaScript).

    Nosotros definimos la funcin que queremos pasara ejecutar justo ah en el lugardonde ejecutar espera su primer parmetro.

    De esta manera, no necesitamos darle a la funcinun nombre, por lo que esta funcin esllamada funcin annima.

    Esta es una primera ojeada a lo que me gusta llamarJavaScript "avanzado". Pero tommoslo paso apaso. Por ahora, aceptemos que en JavaScript,nosotros podemos pasar una funcin como unparmetro cuando llamamos a otra funcin.Podemos hacer esto asignando nuestra funcin a

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 22/78

    una variable, la cual luego pasamos, o definiendo lafuncin a pasar en el mismo lugar.

    De Qu manera el pasarfunciones hace que nuestroservidor HTTP funcioneCon este conocimiento, Volvamos a nuestro servidorHTTP minimalista:

    var http = require("http");

    http.createServer(function(request, response) { response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Mundo"); response.end();}).listen(8888);

    A estas alturas, debera quedar claro lo que estamoshaciendo ac: Estamos pasndole a lafuncincreateServer una funcin annima.

    Podemos llegar a lo mismo refactorizando nuestrocdigo as:

    var http = require("http");

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 23/78

    function onRequest(request, response) { response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Mundo"); response.end();}

    http.createServer(onRequest).listen(8888);

    Quizs ahora es un buen momento para preguntar:Por Qu estamos haciendo esto de esta manera?

    Callbacks Manejadas porEventosLa respuesta a) No es algo fcil de explicar (almenos para m), y b) Yace en la naturaleza mismade como Node.js trabaja: Est orientado al evento,esa es la razn de por qu es tan rpido.

    Podras tomarte un tiempo para leer este excelentepost (en ingls) de FelixGeisendrdfer: Understanding node.js para algunaexplicacin de trasfondo.

    Al final todo se reduce al hecho que Node.js trabajaorientado al evento. Ah, y s, yo tampoco s

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 24/78

    exactamente qu significa eso. Pero voy a hacer unintento de explicar, el porqu esto tiene sentido paranosotros, que queremos escribir aplicaciones web enNode.js.

    Cuando nosotros llamamos almtodo http.createServer, por supuesto que no sloqueremos que el servidor se quede escuchando enalgn puerto, sino que tambin queremos hacer algocuando hay una peticin HTTP a este servidor.

    El problema es, que esto sucede de maneraasincrnica: Puede suceder en cualquier momento,pero solo tenemos un nico proceso en el cualnuestro servidor corre.

    Cuando escribimos aplicaciones PHP, esto no nosmolesta en absoluto: cada vez que hay una peticinHTTP, el servidor web (por lo general Apache)genera un nuevo proceso solo para esta peticin, yempieza el script PHP indicado desde cero, el cuales ejecutado de principio a fin.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 25/78

    As que respecto al control de flujo, estamos en elmedio de nuestro programa en Node.js, cuando unanueva peticin llega al puerto 8888: Cmomanipulamos esto sin volvernos locos?

    Bueno, esta es la parte donde el diseo orientado alevento de Node.js / JavaScript de verdad ayuda,aunque tengamos que aprender nuevos conceptospara poder dominarlo. Veamos como estosconceptos son aplicados en nuestro cdigo deservidor.

    Nosotros creamos el servidor, y pasamos unafuncin al mtodo que lo crea. Cada vez que nuestroservidor recibe una peticin, la funcin que lepasamos ser llamada.

    No sabemos qu es lo que va a suceder, pero ahoratenemos un lugar donde vamos a poder manipularla peticin entrante. Es la funcin que pasamos, sinimportar si la definimos o si la pasamos de maneraannima.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 26/78

    Este concepto es llamado uncallback (N. del T.: delingls: call = llamar; y back = de vuelta). Nosotrospasamos una funcin a algn mtodo, y el mtodoocupa esta funcin para llamar (call) de vuelta(back) si un evento relacionado con este mtodoocurre.

    Al menos para m, esto tom algn tiempo para serentendido. Lee el articulo del blog de Felix de nuevosi todava no te sientes seguro.

    Juguemos un poco con este nuevo concepto.Podemos probar que nuestro cdigo continadespus de haber creado el servidor, incluso si no hasucedido ninguna peticin HTTP y la funcincallback que pasamos no ha sido llamada?Probemos:

    var http = require("http");

    function onRequest(request, response) { console.log("Peticion Recibida."); response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Mundo"); response.end();}

    http.createServer(onRequest).listen(8888);

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 27/78

    console.log("Servidor Iniciado.");

    Noten que utilizo console.log para entregar un textocada vez que la funcin onRequest (nuestrocallback) es gatillada, y otro textodespus de iniciarnuestro servidor HTTP.

    Cuando iniciamos esta aplicacin (con nodeserver.js, como siempre). Esta inmediatamenteescribir en pantalla "Servidor Iniciado" en la lneade comandos. Cada vez que hagamos una peticin anuestro servidor(abriendohttp://localhost:8888/ en nuestrobrowser), el mensaje "Peticion Recibida." va a serimpreso en la lnea de comandos.

    Esto es JavaScript del lado del servidor asincrnicoy orientado al evento con callbacks en accin :-)

    (Toma en cuenta que nuestro servidorprobablemente escribir "Peticin Recibida." aSTDOUT dos veces al abrir la pgina en un browser.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 28/78

    Esto es porque la mayora de los browsers van atratar de cargar el favicon mediante la peticinhttp://localhost:8888/favicon.ico cada vez queabras http://localhost:8888/).

    Como nuestro Servidormanipula las peticionesOK, analicemos rpidamente el resto del cdigo denuestro servidor, esto es, el cuerpo de nuestrafuncin de callback onRequest().

    Cuando la callback es disparada y nuestrafuncin onRequest() es gatillada, dos parmetrosson pasados a ella: request y response.

    Estos son objetos, y puedes usar sus mtodos paramanejar los detalles de la peticin HTTP ocurrida yresponder a la peticin (en otras palabras enviaralgo de vuelta al browser que hizo la peticin a tuservidor).

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 29/78

    Y eso es lo que nuestro cdigo hace: cada vez queuna peticin es recibida, usa lafuncinresponse.writeHead() para enviar unestatus HTTP 200 y un content-type (parmetro quedefine que tipo de contenido es) en el encabezado dela respuesta HTTP, y lafuncinresponse.write() para enviar el texto "HolaMundo" en el cuerpo de la respuesta.

    Por ltimo, nosotros llamamosresponse.end() parafinalizar nuestra respuesta.

    Hasta el momento, no nos hemos interesado por losdetalles de la peticin, y ese es el porqu no hemosocupado el objeto requestcompletamente.

    Encontrando un lugar paranuestro mdulo de servidorOK, promet que volveramos a al Cmo organizarnuestra aplicacin. Tenemos el cdigo de nuestroservidor HTTP muy bsico en el archivo server.js, y

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 30/78

    mencion que es comn tener un archivo principalllamado index.js, el cual es usado para arrancar ypartir nuestra aplicacin haciendo uso de los otrosmdulos de la aplicacin (como el mdulo deservidor HTTP que vive en server.js).

    Hablemos de como podemos hacer que nuestroserver.js sea un verdadero mdulo Node.js y quepueda ser usado por nuestro pronto-a-ser-escritoarchivo principal index.js.

    Como habrn notado, ya hemos usado mdulos ennuestro cdigo, como ste:

    var http = require("http");

    ...

    http.createServer(...);

    En algn lugar dentro de Node.js vive un mdulollamado "http", y podemos hacer uso de ste ennuestro propio cdigo requirindolo y asignando elresultado del requerimiento a una variable local.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 31/78

    Esto transforma a nuestra variable local en unobjeto que acarrea todos los mtodos pblicos queel mdulohttp provee.

    Es prctica comn elegir el nombre del mdulocomo nombre para nuestra variable local, perosomos libres de escoger cualquiera que nos guste:

    var foo = require("http");

    ...

    foo.createServer(...);

    Bien. Ya tenemos claro como hacer uso de losmdulos internos de Node.js. Cmo hacemos paracrear nuestros propios mdulos, y Cmo losutilizamos?

    Descubrmoslo transformando nuestroscript server.js en un mdulo real.

    Sucede que, no tenemos que transformarlo tanto.Hacer que algn cdigo sea un Mdulo, significaque necesitamos exportarlas partes de su

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 32/78

    funcionalidad que queremos proveer a otros scriptsque requieran nuestro mdulo.

    Por ahora, la funcionalidad que nuestro servidorHTTP necesita exportar es simple: Permitir a losscripts que utilicen este mdulo arrancar elservidor.

    Para hacer esto posible, dotaremos al cdigo denuestro servidor de una funcin llamada inicio, yexportaremos esta funcin:

    var http = require("http");

    function iniciar() { function onRequest(request, response) { console.log("Peticin Recibida."); response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Mundo"); response.end(); }

    http.createServer(onRequest).listen(8888); console.log("Servidor Iniciado.");}

    exports.iniciar = iniciar;

    De este modo, Podemos crear nuestro propioarchivo principalindex.js, y arrancar nuestroservidor HTTP all, aunque el cdigo para el

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 33/78

    servidor este en nuestro archivoserver.js.

    Crea un archivo index.js con el siguiente contenido:

    var server = require("./server");

    server.iniciar();

    Como puedes ver, nosotros utilizamos nuestromdulo de servidor tal como cualquier otro mdulointerno: requiriendo el archivo donde estcontenido y asignndolo a una variable, con lasfunciones que tenga 'exportadas' disponibles paranosotros.

    Eso es. Podemos ahora arrancar nuestra aplicacinpor medio de nuestro script principal, y va a hacerexactamente lo mismo:

    node index.js

    Bien, ahora podemos poner las diferentes partes denuestra aplicacin en archivos diferentes y

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 34/78

    enlazarlas juntas a travs de la creacin de estosmdulos.

    Tenemos slo la primera parte de nuestra aplicacinen su lugar: Podemos recibir peticiones HTTP. Peronecesitamos hacer algo con ellas - necesitamosreaccionar de manera diferente, dependiendo deque URL el browser requiera de nuestro servidor.

    Para una aplicacin muy simple, podras hacer estodirectamente dentro de una funcin decallbackOnRequest(). Pero, como dije, agreguemosun poco ms de abstraccin, de manera de hacernuestra aplicacin ms interesante.

    Hacer diferentes peticiones HTTP ir a partesdiferentes de nuestro cdigo se llama "ruteo" (N. delT.: routing, en ingls) - bueno, entonces, cremos unmdulo llamado router.

    Qu se necesita para "rutear"peticiones?

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 35/78

    Necesitamos ser capaces de entregar la URLrequerida y los posibles parmetros GET o POSTadicionales a nuestro router, y basado en estos, elrouter debe ser capaz de decidir qu cdigo ejecutar(este "cdigo a ejecutar" es la tercera parte denuestra aplicacin: una coleccin de manipuladoresde peticiones que harn el verdadero trabajo cuandouna peticin es recibida).

    As que, Necesitamos mirar en las peticiones HTTPy extraer la URL requerida, as como los parmetrosGET/POST de ellos. Se puede discutir acerca de sieste procedimiento debe ser parte del router o delservidor (o si lo hacemos un mdulo por s mismo),pero hagamos el acuerdo de hacerlo parte denuestro servidor HTTP por ahora.

    Toda la informacin que necesitamos estdisponible en el objeto request, el que es pasadocomo primer parmetro a nuestra funcincallback onRequest(). Pero para interpretar estainformacin, necesitamos algunos mdulos

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 36/78

    adicionales Node.js, llamados url yquerystring.

    El mdulo url provee mtodos que nos permiteextraer las diferentes partes de una URL (como porejemplo la ruta requerida y el string de consulta),y querystring puede, en cambio, ser usado paraparsear el string de consulta para los parmetrosrequeridos:

    url.parse(string).query | url.parse(string).pathname | | | | | ------ -------------------http://localhost:8888/iniciar?foo=bar&hello=world --- ----- | | | | querystring(string)["foo"] | | querystring(string)["hello"]

    Podemos, por supuesto, tambinutilizar querystring para parsear el cuerpo de unapeticin POST en busca de parmetros, comoveremos ms tarde.

    Agreguemos ahora a nuestra funcin onRequest() la

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 37/78

    lgica requerida para encontrar que ruta URL elbrowser solicit:

    var http = require("http");var url = require("url");

    function iniciar() { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Peticin para " + pathname + " recibida."); response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Mundo"); response.end(); }

    http.createServer(onRequest).listen(8888); console.log("Servidor Iniciado.");}

    exports.iniciar = iniciar;

    Muy Bien. Nuestra aplicacin puede ahoradistinguir peticiones basadas en la ruta URLrequerida - esto nos permite mapear peticioneshacia nuestro manipuladores de peticiones,basndonos en la ruta URL usando nuestro (prontoa ser escrito) router. Luego, podemos construirnuestra aplicacin en una forma REST (N. del T.:RESTful way en Ingls), ya que ahora podemosimplementar una interfaz que sigue los principiosque guan a laIdentificacin de Recursos (ve por

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 38/78

    favor el artculo de Wikipedia acerca de laTransferencia del Estado Representacional parainformacin de trasfondo.

    En el contexto de nuestra aplicacin, esto significasimplemente que seremos capaces de tenerpeticiones para lasURLs/iniciar y /subir manejadas por partesdiferentes de nuestro cdigo. Veremos pronto comotodo esto encaja.

    OK, es hora de escribir nuestro router. Vamos acrear un nuevo archivo llamado router.js, con elsiguiente contenido:

    function route(pathname) { console.log("A punto de rutear una peticion para " + pathname);}

    exports.route = route;

    Por supuesto, este cdigo no est haciendo nada,pero eso est bien por ahora. Empecemos a vercomo vamos a encajar este router con nuestro

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 39/78

    servidor antes de poner ms lgica en el router.

    Nuestro servidor HTTP necesita saber y hacer usode nuestro router. Podemos escribir directamenteesta dependencia a nuestro servidor, pero comohemos aprendido de la manera difcil en nuestrasexperiencias, vamos a acoplar de manera dbil(loose coupling en Ingls) al router y su servidor vainyeccin por dependencia. Para una referencia defondo, leer elArtculo de Martin Fowler (en Ingls).

    Primero extendamos nuestra funcin iniciar() demanera de permitirnos pasar la funcin de ruteo aser usada como parmetro:

    var http = require("http");var url = require("url");

    function iniciar(route) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Peticion para " + pathname + " recibida.");

    route(pathname);

    response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Mundo"); response.end(); }

    http.createServer(onRequest).listen(8888); console.log("Servidor Iniciado.");}

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 40/78

    exports.iniciar = iniciar;

    Y extendamos nuestro index.jsadecuadamente, estoes, inyectando la funcin de ruteo de nuestro routeren el servidor:

    var server = require("./server");var router = require("./router");

    server.iniciar(router.route);

    Nuevamente , estamos pasando una funcin comoparmetros, pero esto ya no es una novedad paranosotros.

    Si arrancamos nuestra aplicacin ahora (nodeindex.js como siempre), y hacemos una peticinpara una URL, puedes ver ahora por las respuestasde la aplicacin que nuestro servidor HTTP haceuso de nuestro router y le entrega el nombre de rutarequerido:

    bash$ node index.jsPeticin para /foo recibida.A punto de rutear una peticion para /foo

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 41/78

    He omitido la molesta respuesta de la peticin para/favicon.ico

    Ejecucin en el reino de losverbosPuedo divagar un vez ms por un momento yhablar acerca de la programacin funcional denuevo?

    Pasar funciones no es slo una consideracintcnica. Con respecto al diseo de software, esto escasi filosfico. Tan solo piensa en ello: en nuestroarchivo de index, podramos haber entregado elobjeto router al servidor, y el servidor hubiesellamado a la funcin route de este objeto.

    De esta manera, podramos haber pasado una cosa,y el servidor hubiese usado esa cosa para haceralgo.Oye, "Cosa Router", Podras por favor rutear estopor m?

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 42/78

    Pero el servidor no necesita la cosa. Slonecesita hacer algo, y para que algo se haga, nonecesitas cosas para nada, slo necesitas acciones.No necesitas sustantivos, sino que necesitas verbos.

    Entender este cambio de mentalidad fundamentalque est en el ncleo de esta idea es lo querealmente me hizo entender la programacinfuncional.

    Y lo entend mientras lea la obra maestra de SteveYegge (en Ingls)Ejecucin en el Reino de losSustantivos. Anda, lela, por favor. Es uno de losmejores artculos relacionados con el software quehaya tenido el placer de encontrar.

    Ruteando a los verdaderosmanipuladores de peticionesVolviendo al tema. Nuestro servidor HTTP y nuestrorouter de peticiones son ahora los mejores amigos yconversan entre ellos, tal y como pretendimos.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 43/78

    Por supuesto, esto no es suficiente, "Rutear"significa que nosotros queremos manipular laspeticiones a distintas URLs de manera, diferente.Nos gustara tener la "lgicas de negocios" parapeticiones de /inicio manejadas en otra funcin,distinta a la que maneja las peticiones para /subir.

    Por ahora, el ruteo "termina" en el router, y el routerno es el lugar donde se est "haciendo algo" con laspeticiones, ya que esto no escalara bien una vez quenuestra aplicacin se haga ms compleja.

    Llamemos a estas funciones, donde las peticionesestn siendo ruteadas, manipuladores depeticiones ( request handlers). Y procedamos constos ahora, porque, a menos que no los tengamosen su lugar, no hay tiene mucho sentido en hacernada con el router por ahora.

    Nueva parte de la aplicacin, significa nuevomdulo - no creo que haya sorpresa ac. Creemosun mdulo llamado requestHandlers (N. del T.: por

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 44/78

    manipuladores de peticin), agreguemos un funcinde ubicacin para cada manipulador de peticin, yexportemos estos como mtodos para el mdulo:

    function iniciar() { console.log("Manipulador de peticin 'iniciar' ha sido llamado.");}

    function subir() { console.log("Manipulador de peticin 'subir' ha sido llamado.");}

    exports.iniciar = iniciar;exports.subir = subir;

    Esto nos permitir atar los manipuladores depeticin al router, dndole a nuestro router algo querutear.

    Llegado a este punto, necesitamos tomar unadecisin: Ingresaremos las rutas del mdulorequestHandlers dentro del cdigo del router (hard-coding), o queremos algo ms de dependencia porinyeccin? Aunque en la dependencia por inyeccin,como cualquier otro patrn, no debera ser usadasimplemente por usarla, en este caso tiene sentidoacoplar el router dbilmente a sus manipuladores

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 45/78

    de peticin, as, de esta manera hacemos que elrouter sea reutilizable.

    Esto significa que necesitamos pasar losmanipuladores de peticin desde nuestro server alrouter, pero esto se siente equivocado, dado que,Por qu tenemos que hacer el camino largo yentregar los manipuladores desde el archivoprincipal al servidor y de ah al router?

    Cmo vamos a pasarlos? Ahora tenemos slo dosmanipuladores, pero en una aplicacin real, estenmero se va a incrementar y variar, y nosotros noqueremos estar a cada momento mapeandopeticiones a manipuladores cada vez que una nuevaURL o manipulador de peticin sea agregado. Y sitenemos un cdigo del tipo if peticion == x thenllama manipulador y en el router, esto se pondracada vez ms feo.

    Un nmero variable de tems, cada uno de ellosmapeados a un string? (en este caso la URL

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 46/78

    requerida) Bueno, esto suena como que un arrayasociativo hara el truco.

    Bueno, este descubrimiento es obscurecido por elhecho que JavaScript no provee arrays asociativos -o s? !Resulta que lo que necesitamos usar sonobjetos si necesitamos un array asociativo!

    Una buena introduccin a esto est (en Ingls)enhttp://msdn.microsoft.com/en-us/magazine/cc163419.aspx, Djame citarte la parterelevante:

    En C++ o C#, cuando hablamos acerca deobjetos, nos estamos refiriendo a instanciasde clases de estructuras. Los objetos tienendistintas propiedades y mtodos,dependiendo en las plantillas (esto es, lasclases) desde donde stos sean instanciados.Este no es el caso con los objetos deJavaScript. En JavaScript, los objetos sonslo colecciones de pares nombre/valor -

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 47/78

    piensa en un objeto JavaScript como en undiccionario con llaves de string.

    Si los objetos JavaScript son slo colecciones depares nombre/valor, Cmo pueden entonces tenermtodos? Bueno, los valores pueden ser strings,nmeros, etc... O Funciones!

    OK, ahora, volviendo finalmente al cdigo. Hemosdecidido que queremos pasar la lista derequestHandlers (manipuladores de peticin) comoun objeto, y para lograr este acoplamiento dbil,necesitamos usar la tcnica de inyectar este objetoen la route()(ruta).

    Empecemos con poner el objeto en nuestro archivoprincipal index.js:

    var server = require("./server");var router = require("./router");var requestHandlers = require("./requestHandlers");

    var handle = {}handle["/"] = requestHandlers.iniciar;handle["/iniciar"] = requestHandlers.iniciar;handle["/subir"] = requestHandlers.subir;

    server.iniciar(router.route, handle);

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 48/78

    (N. del T.: Se Opta por dejar los verbos en Ingls'route' para rutear y 'handle' para manipular).

    Aunque handle es ms una "cosa" (una coleccin demanipuladores de peticin), propongo que lonombremos como un verbo, ya que esto resultar enuna expresin fluida en nuestro router, comoveremos a continuacin:

    Como puedez ver, es realmente simple mapeardiferentes URLs al mismo manipulador depeticiones: Mediante la adicin de un parllave/valor de "/" yrequestHandlers.iniciar,podemos expresar en una forma agradable y limpiaque no slo peticiones a/start, sino que tambinpeticiones a / pueden ser manejadas por elmanipulador inicio.

    Despus de definir nuestro objeto, se lo pasamos alservidor como un parmetro adicional.Modifiquemos nuestro server.js para hacer uso deeste:

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 49/78

    var http = require("http");var url = require("url");

    function iniciar(route, handle) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Peticion para " + pathname + " recibida.");

    route(handle, pathname);

    response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Mundo"); response.end(); }

    http.createServer(onRequest).listen(8888); console.log("Servidor Iniciado.");}

    exports.iniciar = iniciar;

    Lo que hacemos aqu, es chequear si unmanipulador de peticiones para una ruta dadaexiste, y si es as, simplemente llamamos a lafuncin adecuada. Dado que podemos acceder anuestras funciones manipuladoras de peticindesde nuestro objeto de la misma manera quehubisemos podido acceder a un elemento de unarray asociativo, es que tenemos la expresinfluidahandle[pathname](); de la que habl antes,que en otras palabras es: "Porfavor, handle (maneja) este(a) pathname (ruta)".

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 50/78

    Bien, Esto es todo lo que necesitamos para atarservidor, router y manipuladores de peticionesjuntos! Una vez que arranquemos nuestraaplicacin y hagamos una peticin en nuestrobrowser dehttp://localhost:8888/iniciar, vamos aprobar que el manipulador de peticin correcto fue,de hecho, llamado:

    Servidor Iniciado.Peticion para /iniciar recibida.

    A punto de rutear una peticin para /iniciarManipulador de peticion 'iniciar' ha sido llamado.

    Haciendo que los Manipuladoresde Peticiones respondanMuy bien. Ahora, si tan solo los manipuladores depeticin pudieran enviar algo de vuelta al browser,esto sera mucho mejor, cierto?

    Recuerda, que el "Hola Mundo" que tu browserdespliega ante una peticin de una pgina, anviene desde la funcin onRequest en nuestro

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 51/78

    archivo server.js.

    "Manipular Peticiones" no significa otra cosa que"Responder a las Peticiones" despus de todo, asque necesitamos empoderar a nuestrosmanipuladores de peticiones para hablar con elbrowser de la misma manera que lafuncin onRequest lo hace.

    Cmo no se debe hacer esto?La aproximacin directa que nosotros -desarrolladores con un trasfondo en PHP o Ruby -quisieramos seguir es de hecho conducente aerrores: trabaja de manera espectacular al principioy parece tener mucho sentido, y de pronto, las cosasse arruinan en el momento menos esperado.

    A lo que me refiero con "aproximacin directa" esesto: hacer que los manipuladores de peticinretornen - return() - el contenido que ellos quierandesplegar al usuario, y luego, enviar esta data de

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 52/78

    respuesta en la funcinonRequest de vuelta alusuario.

    Tan slo hagamos esto, y luego, veamos por questo no es tan buena idea.

    Empecemos con los manipuladores de peticin yhagmoslos retornar, lo que nosotros queremosdesplegar en el browser. Necesitamosmodificar requestHandlers.js a lo siguiente:

    function iniciar() { console.log("Manipulador de peticion 'iniciar' fue llamado."); return "Hola Iniciar";}

    function subir() { console.log("Manipulador de peticion 'subir' fue llamado."); return "Hola Subir";}

    exports.iniciar = iniciar;exports.subir = subir;

    Bien. De todas maneras, el router necesita retornaral servidor lo que los manipuladores de peticin leretornaron a l. Necesitamos entonceseditar router.js de esta manera:

    function route(handle, pathname) {

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 53/78

    console.log("A punto de rutear una peticion para " + pathname); if (typeof handle[pathname] === 'function') { return handle[pathname](); } else { console.log("No se encontro manipulador para " + pathname); return "404 No Encontrado"; }}

    exports.route = route;

    Como puedes ver, nosotros tambin retornaremosalgn texto si la peticin no es ruteada.

    Por ltimo, pero no menos importante, necesitamosrefactorizar nuestro servidor para hacerlo responderal browser con el contenido que los manipuladoresde peticin le retornaron via el router,transformando de esta manera aserver.js en:

    var http = require("http");var url = require("url");

    function iniciar(route, handle) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Peticion para " + pathname + " recibida.");

    response.writeHead(200, {"Content-Type": "text/html"}); var content = route(handle, pathname) response.write(content); response.end(); }

    http.createServer(onRequest).listen(8888); console.log("Servidor Iniciado.");}

    exports.iniciar = iniciar;

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 54/78

    Si nosotros arrancamos nuestra aplicacin re-escrita, todo va a funcionar a las mil maravillas:hacerle una peticinahttp://localhost:8888/iniciarresulta en "HolaIniciar" siendo desplegado en el browser, hacerleuna peticin ahttp://localhost:8888/subir nos da"Hola Subir", y la peticinahttp://localhost:8888/foo produce "404 NoEncontrado".

    OK, entonces Por qu esto es un problema? Larespuesta corta es: debido a que si uno de losmanipuladores de peticin quisiera hacer uso deuna operacin no-bloqueante (non-blocking) en elfuturo, entonces esta configuracin, como latenemos, sera problemtica.

    Tommosnos algn tiempo para la respuesta larga.

    Bloqueante y No-BloqueanteComo se dijo, los problemas van a surgir cuando

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 55/78

    nosotros incluyamos operaciones no-bloqueantes enlos manipuladores de peticin. Pero hablemosacerca de las operaciones bloqueantes primero,luego, acerca de las operaciones no-bloqueantes.

    Y, en vez de intentar explicar que es lo que significa"bloqueante" y "no bloqueante", demostremosnosotros mismo que es lo que sucede su agregamosuna operacin bloqueante a nuestrosmanipuladores de peticin.

    Para hacer esto, modificaremos nuestromanipulador de peticininiciar para hacer unaespera de 10 segundos antes de retornar su string"Hola Iniciar". Ya que no existe tal cosacomo sleep() en JavaScript, usaremos un hackingenioso para ello.

    Por favor, modificarequestHandlers.js como sigue:

    function iniciar() { console.log("Manipulador de peticion 'iniciar' fue llamado.");

    function sleep(milliSeconds) { // obten la hora actual var startTime = new Date().getTime();

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 56/78

    // atasca la cpu while (new Date().getTime() < startTime + milliSeconds); }

    sleep(10000); return "Hola Iniciar";}

    function subir() { console.log("Manipulador de peticion 'subir' fue llamado."); return "Hola Subir";}

    exports.iniciar = iniciar;exports.subir = subir;

    Dejemos claros que es lo que esto hace: cuando lafuncin iniciar() es llamada, Node.js espera 10segundos y slo ah retorna "Hola Iniciar". Cuandoest llamando asubir(), retorna inmediatamente, lamisma manera que antes.

    (Por supuesto la idea es que te imagines que, en vezde dormir por 10 segundos, exista una operacinbloqueante verdadera en iniciar(), como algn tipode calculo de largo aliento.)

    Vemos qu es lo que este cambio hace.

    Como siempre, necesitamos reiniciar nuestroservidor. Esta vez, te pido sigas un "protocolo" un

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 57/78

    poco ms complejo de manera de ver que sucede:Primero, abre dos ventanas de browser o tablas. Enla primera ventana, por favoringresahttp://localhost:8888/iniciar en la barra dedirecciones, pero no abras an esta url!

    En la barra de direcciones de la segunda ventana debrowser, ingresa http://localhost:8888/subiry,nuevamente, no presiones enter todava.

    Ahora, haz lo siguiente: presiona enter en laprimera ventana ("/iniciar"), luego, rpidamentecambia a la segunda ventana ("/subir") y presionaenter, tambin.

    Lo que veremos ser lo siguiente: La URL /iniciotoma 10 segundos en cargar, tal cual esperamos.Pero la URL /subir tambin toma 10 segundos paracargar, Aunque no hay definido un sleep() en elmanipulador de peticiones correspondiente!

    Por qu? simple, porque inicio()contiene una

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 58/78

    operacin bloqueante. En otras palabras "Estbloqueando el trabajo de cualquier otra cosa".

    He ah el problema, porque, el dicho es: "EnNode.js, todo corre en paralelo, excepto tu cdigo".

    Lo que eso significa es que Node.js puede manejarun montn de temas concurrentes, pero no lo hacedividiendo todo en hilos (threads) - de hecho,Node.js corre en un slo hilo. En vez de eso, lo haceejecutando un loop de eventos, y nosotros, losdesarrolladores podemos hacer uso de esto -Nosotros debemos evitar operaciones bloqueantesdonde sea posible, y utilizar operaciones no-bloqueantes en su lugar.

    Lo que exec() hace, es que, ejecuta un commando deshell desde dentro de Node.js. En este ejemplo,vamos a usarlo para obtener una lista de todos losarchivos del directorio en que nos encontramos ("ls-lah"), permitindonos desplegar esta lista en elbrowser de un usuario que este peticionando la

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 59/78

    URL /inicio.

    Lo que el cdigo hace es claro: crea una nuevavariable content() (con el valor incial de "vacio"),ejecuta "ls -lah", llena la variable con el resultado, ylo retorna.

    Como siempre, arrancaremos nuestra aplicacin yvisitaremoshttp://localhost:8888/iniciar.

    Lo que carga una bella pgina que despliega elstring "vacio". Qu es lo que est incorrecto ac?

    Bueno, como ya habrn adivinado,exec() hace sumagia de una manera no-bloqueante. Buena cosaesto, porque de esta manera podemos ejecutaroperaciones de shell muy caras en ejecucin (como,por ejemplo, copiar archivos enormes o cosassimilares) sin tener que forzar a nuestra aplicacin adetenerse como lo hizo la operacin sleep.

    (Si quieres probar esto, reemplaza "ls -lah" con unaoperacin ms cara como "find /").

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 60/78

    Pero no estaramos muy felices si nuestra eleganteaplicacin no bloqueante no desplegara algnresultado, cierto?.

    Bueno, entonces, arreglmosla. Y mientras estamosen eso, tratemos de entender por qu la arquitecturaactual no funciona.

    El problema es que exec(), para poder trabajar demanera no-bloqueante, hace uso de una funcin decallback.

    En nuestro ejemplo, es una funcin annima, la cuales pasada como el segundo parmetro de la llamadaa la funcin exec():

    function (error, stdout, stderr) { content = stdout;}

    Y aqu yace la raz de nuestro problema: nuestrocdigo es ejecutado de manera sincrnica, lo quesignifica que inmediatamente despus de llamara exec(), Node.js contina ejecutando return

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 61/78

    content;. En este punto, contenttodava est vaco,dado el hecho que la funcin de callback pasadaaexec() no ha sido an llamada -porque exec() opera de manera asincrnica.

    Ahora, "ls -lah" es una operacin sencilla y rpida (amenos, claro, que hayan millones de archivos en eldirectorio). Por lo que es relativamente expedtollamar al callback - pero de todas maneras estosucede de manera asincrnica.

    Esto se hace ms obvio al tratar con un comandoms costoso: "find /" se toma un minuto en mimaquina, pero si reemplazo "ls -lah" con "find /" enel manipulador de peticiones, yo reciboinmediatamente una respuesta HTTP cuando abrola URL /inicio - est claro que exec()hace algo en eltrasfondo, mientras que Node.js mismo continacon el flujo de la aplicacin, y podemos asumir quela funcin de callback que le entregamosa exec() ser llamada ssolo cuando el comando"find /" haya terminado de correr.

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 62/78

    Pero, cmo podemos alcanzar nuestra meta, la demostrarle al usuario una lista de archivos deldirectorio actual?

    Bueno, despus de aprender comono hacerlo,discutamos cmo hacer que nuestrosmanipuladores de peticin respondan a losrequirimientos del browser de la manera correcta.

    Respondiendo a los Manipuladoresde Peticin con Operaciones NoBloqueantesAcabo de usar la frase "la manera correcta". Cosapeligrosa. Frecuentemente, no existe una nica"manera correcta".

    Pero una posible solucin para esto, frecuente conNode.js es pasar funciones alrededor. Examinemosesto.

    Ahora mismo, nuestra aplicacin es capaz detransportar el contenido desde los manipuladores

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 63/78

    de peticin al servidor HTTP retornndolo haciaarriba a travs de las capas de la aplicacin(manipulador de peticin -> router -> servidor).

    Nuestro nuevo enfoque es como sigue: en vez dellevar el contenido al servidor, llevaremos elservidor al contenido. Para ser ms precisos,inyectaremos el objeto response(respuesta) (desdenuestra funcin de callback deservidor onRequest()) a travs de nuestro router alos manipuladores de peticin. Los manipuladoressern capaces de usar las funciones de este objetopara responder a las peticiones ellos mismos.

    Suficientes explicaciones, aqu hay una receta paso apaso de como cambiar nuestra aplicacin.

    Empecemos con nuestro servidor,server.js:

    var http = require("http");var url = require("url");

    function iniciar(route, handle) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Peticion para " + pathname + " recibida.");

    route(handle, pathname, response);

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 64/78

    }

    http.createServer(onRequest).listen(8888); console.log("Servidor Iniciado.");}

    exports.iniciar = iniciar;

    En vez de esperar un valor de respuesta desde lafuncin route(), pasmosle un tercer parmetro:nuestro objeto response. Es ms, removamoscualquier llamada aresponse desde elmanipuladoronRequest(), ya que ahora esperamosque route se haga cargo de esto.

    Ahora viene router.js:

    function route(handle, pathname, response) { console.log("A punto de rutear una peticion para " + pathname); if (typeof handle[pathname] === 'function') { handle[pathname](response); } else { console.log("No hay manipulador de peticion para " + pathname); response.writeHead(404, {"Content-Type": "text/html"}); response.write("404 No Encontrado"); response.end(); }}

    exports.route = route;

    Mismo patrn: En vez de esperar que retorne unvalor desde nuestros manipuladores de peticin,

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 65/78

    nosotros traspasamos el objetoresponse.

    Si no hay manipulador de peticin para utilizar,ahora nos hacemos cargo de responder conadecuados encabezado y cuerpo "404".

    Y por ltimo, pero no menos importante,modificamos arequestHandlers.js (el archivo demanipuladores de peticin).

    var exec = require("child_process").exec;

    function iniciar(response) { console.log("Manipulador de peticin 'iniciar' fue llamado.");

    exec("ls -lah", function (error, stdout, stderr) { response.writeHead(200, {"Content-Type": "text/html"}); response.write(stdout); response.end(); });}

    function subir(response) { console.log("Manipulador de peticin 'subir' fue llamado."); response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Subir"); response.end();}

    exports.iniciar = iniciar;exports.subir = subir;

    Nuestras funciones manipuladoras necesitanaceptar el parmetro de respuesta response, y de

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 66/78

    esta manera, hacer uso de l de manera deresponder a la peticin directamente.

    El manipulador iniciar responder con el callbackannimo exec(), y el manipulador subir replicarsimplemente con "Hola Subir", pero esta vez,haciendo uso del objetoresponse.

    Si arrancamos nuestra aplicacin de nuevo (nodeindex.js), esto debera funcionar de acuerdo a loesperado.

    Si quieres probar que la operacin cara dentrode /iniciar no bloquear ms las peticionespara /subir que sean respondidas inmediatamente,entonces modifica tuarchivorequestHandlers.js como sigue:

    var exec = require("child_process").exec;

    function iniciar(response) { console.log("Manipulador de peticin 'iniciar' fue llamado.");

    exec("find /", { timeout: 10000, maxBuffer: 20000*1024 }, function (error, stdout, stderr) { response.writeHead(200, {"Content-Type": "text/html"}); response.write(stdout); response.end(); });

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 67/78

    }

    function subir(response) { console.log("Manipulador de peticin 'subir' fue llamado."); response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Subir"); response.end();}

    exports.iniciar = iniciar;exports.subir = subir;

    Esto har que las peticiones HTTPahttp://localhost:8888/iniciartomen al menos 10segundos, pero, las peticionesahttp://localhost:8888/subir sean respondidasinmediatamente, incluso si /iniciar todava est enproceso.

    Sirviendo algo tilHasta ahora, lo que hemos hecho es todo simpticoy bonito, pero no hemos creado an valor para losclientes de nuestro sitio web ganador de premios.

    Nuestro servidor, router y manipuladores depeticin estn en su lugar, as que ahora podemosempezar a agregar contenido a nuestro sitio que

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 68/78

    permitir a nuestros usuarios interactuar y andar atravs de los casos de uso de elegir un archivo, subireste archivo, y ver el archivo subido en el browser.Por simplicidad asumiremos que slo los archivosde imagen van a ser subidos y desplegados a travsde la aplicacin.

    OK, vemoslo paso a paso, pero ahora, con lamayora de las tcnicas y principios de JavaScriptexplicadas, acelermoslo un poco al mismo tiempo.

    Aqu, paso a paso significa a grandes razgos dospasos: vamos a ver primero como manejarpeticiones POST entrantes (pero no subidas dearchivos), y en un segundo paso, haremos uso de unmodulo externo de Node.js para la manipulacin desubida de archivos. He escogido este alcance pordos razones:

    Primero, manejar peticiones POST bsicas esrelativamente simple con Node.js, pero an nosensea lo suficiente para que valga la pena

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 69/78

    ejercitarlo. Segundo, manejar las subidas de archivos (i.e.peticiones POST multiparte) no es simple conNode.js, consecuentemente est ms all del alcancede este tutorial, pero el aprender a usar un moduloexterno es una leccin en s misma que tiene sentidode ser includa en un tutorial de principiantes.

    Manejando Peticiones POSTMantengamos esto ridculamente simple:presentaremos un rea de texto que pueda serllenada por el usuario y luego enviada al servidor enuna peticin POST. Una vez recibida y manipuladaesta peticin, despliegaremos el contenido del reade texto.

    El HTML para el formulario de esta rea de textonecesita ser servida por nuestro manipulador depeticin /iniciar, as que agregumoslo deinmediato. En el archivo requestHandlers.js:

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 70/78

    function iniciar(response) { console.log("Manipulador de peticiones 'iniciar' fue llamado.");

    var body = ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ '';

    response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end();}

    function subir(response) { console.log("Manipulador de peticiones 'subir' fue llamado."); response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hola Subir"); response.end();}

    exports.iniciar = iniciar;exports.subir = subir;

    Ahora, si esto no va a ganar los Webby Awards,entonces no se que podra. Haciendo lapeticinhttp://localhost:8888/iniciar en tubrowser, deberas ver un formulario muy simple. Sino, entonces probablemente no has reiniciado laaplicacin.

    Te estoy escuchando: tener contenido de vista justo

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 71/78

    en el manipulador de peticin es feo. Sin embargo,he decidido no incluir ese nivel extra de abstraccin(esto es, separar la lgica de vista y controlador) eneste tutorial, ya que pienso que es no nos enseanada que valga la pena saber en el contexto deJavaScript o Node.js.

    Mejor usemos el espacio que queda en pantalla paraun problema ms interesante, esto es, manipular lapeticin POST que dar con nuestro manipuladorde peticin /subircuando el usuario enve esteformulario.

    Ahora que nos estamos convirtiendo en "noviciosexpertos", ya no nos sorprende el hecho quemanipular informacin de POST este hecho de unamanera no bloqueante, mediante el uso de llamadasasincrnicas.

    Lo que tiene sentido, ya que las peticiones POSTpueden ser potencialmente muy grandes - nadadetiene al usuario de introducir texto que tenga

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 72/78

    muchos megabytes de tamao. Manipular este granvolumen de informacin de una vez puede resultaren una operacin bloqueante.

    Para hacer el proceso completo no bloqueante.Node.js le entrega a nuestro cdigo la informacinPOST en pequeos trozos con callbacks que sonllamadas ante determinados eventos. Estos eventosson data (un nuevo trozo de informacin POST hallegado) y end(todos los trozos han sido recibidos).

    Necesitamos decirle a Node.js que funciones llamarde vuelta cuando estos eventos ocurran. Esto eshecho agregando listeners (N. del T.: delverbo listen - escuchar) al objeto de peticin(request) que es pasado a nuestrocallback onRequest cada vez que una peticin HTTPes recibida.

    Esto bsicamente luce as:

    request.addListener("data", function(chunk) { // funcion llamada cuando un nuevo trozo (chunk) // de informacion (data) es recibido.});

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 73/78

    request.addListener("end", function() { // funcion llamada cuando todos los trozos (chunks) // de informacion (data) han sido recibidos.});

    La pregunta que surge es dnde implementar stalgica. Nosotros slo podemos acceder alobjetorequest en nuestro servidor - no se lo estamospasando al router o a los manipuladores depeticin, como lo hicimos con el objeto response.

    En mi opinin, es un trabajo del servidor HTTP dedarle a la aplicacin toda la informacin de unapeticin que necesite para hacer su trabajo. Luego,sugiero que manejemos el procesamiento de lapeticin de POST en el servidor mismo y pasemos lainformacin final al router y a los manipuladores depeticin, los que luego decidirn que hacer con sta.

    Entonces, la idea es poner loscallbacks data y end en el servidor, recogiendo todolos trozos de informacin POST en el callbackdata, yllamando al router una vez recibido el evento end,

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 74/78

    mientras le entregamos los trozos de informacinrecogidos al router, el que a su vez se los pasa a losmanipuladores de peticin.

    Aqu vamos, empezando conserver.js:

    var http = require("http");var url = require("url");

    function iniciar(route, handle) { function onRequest(request, response) { var dataPosteada = ""; var pathname = url.parse(request.url).pathname; console.log("Peticion para " + pathname + " recibida.");

    request.setEncoding("utf8");

    request.addListener("data", function(trozoPosteado) { dataPosteada += trozoPosteado; console.log("Recibido trozo POST '" + trozoPosteado + "'."); });

    request.addListener("end", function() { route(handle, pathname, response, dataPosteada); });

    }

    http.createServer(onRequest).listen(8888); console.log("Servidor Iniciado");}

    exports.iniciar = iniciar;

    Bsicamente hicimos tres cosas aqu: primero,definimos que esperamos que la codificacin de lainformacin recibida sea UTF-8, agregamos unlistener de eventos para el evento "data" el cual llena

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 75/78

    paso a paso nuestra variabledataPosteada cada vezque un nuevo trozo de informacin POST llega, ymovemos la llamada desde nuestro router alcallback del eventoend de manera de asegurarnosque slo sea llamado cuando toda la informacinPOST sea reunida. Adems, pasamos la informacinPOST al router, ya que la vamos a necesitar ennuestros manipuladores de eventos.

    Agregar un loggueo de consola cada vez que untrozo es recibido es una mala idea para cdigo deproduccin (megabytes de informacin POST,recuerdan?, pero tiene sentido para que veamosque pasa.

    Mejoremos nuestra aplicacin. En la pgina /subir,desplegaremos el contenido recibido. Para haceresto posible, necesitamos pasar ladataPosteada alos manipuladores de peticin, en router.js.

    function route(handle, pathname, response, postData) { console.log("A punto de rutear una peticion para " + pathname); if (typeof handle[pathname] === 'function') { handle[pathname](response, postData); } else {

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 76/78

    console.log("No se ha encontrado manipulador para " + pathname); response.writeHead(404, {"Content-Type": "text/html"}); response.write("404 No encontrado"); response.end(); }}

    exports.route = route;

    Y en requestHandlers.js, inclumos la informacinde nuestro manipulador de peticin subir:

    function iniciar(response, postData) { console.log("Manipulador de Peticion 'iniciar' fue llamado.");

    var body = ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''; response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end();}

    function subir(response, dataPosteada) { console.log("Manipulador de Peticion 'subir' fue llamado."); response.writeHead(200, {"Content-Type": "text/html"}); response.write("Tu enviaste: " + dataPosteada); response.end();}

    exports.iniciar = iniciar;exports.subir = subir;

    Eso es, ahora somos capaces de recibir informacin

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 77/78

    POST y usarla en nuestros manipuladores depeticin.

    Una ltima cosa para este tema: lo que le estamospasando al router y los manipuladores de peticines el cuerpo (body) de nuestra peticin POST.Probablemente necesitemos consumir los camposindividuales que conforman la informacin POST,en este caso, el valor del campo text.

    Nosotros ya hemos ledo acerca delmdulo querystring, el que nos ayuda con esto:

    var querystring = require("querystring");

    function iniciar(response, postData) { console.log("Manipulador de peticion 'inicio' fue llamado.");

    var body = ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ '';

    response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end();}

    function subir(response, dataPosteada) {

  • 8/4/2015 El Libro para Principiantes en Node.js Un tutorial completo de node.js

    data:text/html;charset=utf-8,%3Ch1%20style%3D%22margin-left%3A%20-33px%3B%20margin-top%3A%20-109px%3B%20font 78/78

    console.log("Manipulador de peticion 'subir' fue llamado."); response.writeHead(200, {"Content-Type": "text/html"}); response.write("Tu enviaste el texto: : " + querystring.parse(dataPosteada)["text"]); response.end();}

    exports.iniciar = iniciar;exports.subir = subir;

    Bueno, para un tutorial de principiantes, esto estodo lo que diremos acerca de la informacin POST.

    La prxima vez, hablaremos sobre como usar elexcelente mdulonode-formidable para permitirnoslograr nuestro caso de uso final: subir y desplegarimgenes.