Tutorial de Express.js

Archivada en Desarrollo Web

Tutorial de Express.js

Motivación

Después de interntar con varias soluciones replicar el cuadro de mando integral usando Node.js, me di cuneta que carecía de una parte muy importante: no sabía qué era y como se usaba Express.js que es la base de todos estos frameworks. En esta serie de artículos, voy a eliminar esa carencia.

Qué es Express.js

Express.js es un marco de trabajo para desarrollo web que se basa en el módulo http del núcleo de Node.js y componentes de Connect. Esos componentes se llaman intermediarios o middlewares y son la piedra angular de la filosofía del framework, es decir, la confirguración sobre convención. En otras palabras, los desarrolladores son libres de elegir las librerías que necesiten para un proyecto particular lo que proporciona una gran libertad y personalización.

Si de verdad intentáramos crear una aplicación como el CMI usando solo los módulos del núcleo de Node.js, estaríamos tratando de inventar el hilo negro, escribiendo uno y otra vez el mismo código para realizar tares similares, como:

  • Evaluar el contenido de las solicitudes HTTP
  • Evaluación de cookies
  • Gestión de sesiones
  • Organizar las rutas como una cadena de condiciones if, basándonos en la URL y el método de la solicitud
  • Determinar los encabezados de respuesta adecuado al tipo de datos.

Express.js resuelve estos y muchos otros problemas. También proporciona una estructura tipo MVC para nuestras aplicaciones web. Estas aplicaciones pueden ir desde una API REST hasta una aplicación completa y escalable full stack con comunicación en tiempo real.

Cómo funciona Express.js

Las aplicaciones Express.js tienen por lo general un punto de entrada o archivo principal. En dicho archivo realizamos lo siguiente:

  1. Se incluyen las dependencias de terceros, así como los módulos propios, como controladores, utilerías, ayudas y modelos.
  2. Se configura Express.js, por ejemplo, el motor de plantillas y las extensiones de archivo.
  3. Se definen los intermediarios o middleware, como los gestores de errores, de archivos estáticos, cookies y evalueadores o parsers.
  4. Se definen las rutas.
  5. Se conecta las bases de datos, como MongoDB, Redes o PostgreSQL.
  6. Inicia la aplicación.

Cuando una aplicación Express.js se está ejecutando, escucha las solicitudes. Cada solicitud entrante es procesada de acuerdo a una cadena definida de intermediarios y rutas empezando de arriba a abajo. Este concepto es muy importante porque nos permite tener un control sobre el flujo de ejecución. Por ejemplo, podemos tener múltiples funciones para manejar coada solicitud, algúnas de ellas se ejecutarán en medio del procesamiento1:

  1. Analizan la información de las cookies y al terminan, continúan al siguiente paso.
  2. Analizan los parámetros de la URL, y al termina continuán con el siguiente paso.
  3. Obtienen información de la base de datos, usando el valor de los parámetros si el usuario está autorizado (por cookie o por sesión) y continua al siguiente paso.
  4. Muestra el siguiente paso y termina la respuesta.

Instalación

Express.js viene en dos versiones, una que podemos llamar CLI que es en realidad un generador de Yeoman y con un simple comando cra una estructura completa; la otra es un módulo de Node.js, es decir una dependencia.

Dado que nuestro objetivo es aprender desde la raíz, vamos a usar la segunda opción.

Creación del proyecto

Vamos a crear un nuevo directorio nspaces y dentro vamos a iniciar nuestro proyecto.

$ yarn init                                                     
yarn init v0.24.5
question name (nspaces): 
question version (1.0.0): 0.1.0
question description: El nuevo cuadro de mando en clave de ECMAScript
question entry point (index.js): 
question repository url: 
question author: Javier Sanchez Toledano
question license (MIT): 
success Saved package.json
Done in 63.74s.

Esto produce un archivo packages.json con el siguiente contenido.

$ cat package.json                                                         
{
  "name": "nspaces",
  "version": "0.1.0",
  "description": "El nuevo cuadro de mando en clave de ECMAScript",
  "main": "index.js",
  "author": "Javier Sanchez Toledano",
  "license": "MIT"
}

Ahora vamos a agregar el módulo express a nuestras dependencias, con la siguiente orden:

$ yarn add express

Este comando instala todas las dependencias que necesita express

yarn add v0.24.5
info No lockfile found.  
[1/4] Resolving packages...  
[2/4] Fetching packages...  
[3/4] Linking dependencies...  
[4/4] Building fresh packages...  
success Saved lockfile.
success Saved 42 new dependencies.
├─ accepts@1.3.3
├─ array-flatten@1.1.1
├─ content-disposition@0.5.2
├─ content-type@1.0.2
├─ cookie-signature@1.0.6
├─ cookie@0.3.1
├─ debug@2.6.7
├─ depd@1.1.0
├─ destroy@1.0.4
├─ ee-first@1.1.1
├─ encodeurl@1.0.1
├─ escape-html@1.0.3
├─ etag@1.8.0
├─ express@4.15.3
├─ finalhandler@1.0.3
├─ forwarded@0.1.0
├─ fresh@0.5.0
├─ http-errors@1.6.1
├─ inherits@2.0.3
├─ ipaddr.js@1.3.0
├─ media-typer@0.3.0
├─ merge-descriptors@1.0.1
├─ methods@1.1.2
├─ mime-db@1.27.0
├─ mime-types@2.1.15
├─ mime@1.3.4
├─ ms@2.0.0
├─ negotiator@0.6.1
├─ on-finished@2.3.0
├─ parseurl@1.3.1
├─ path-to-regexp@0.1.7
├─ proxy-addr@1.1.4
├─ qs@6.4.0
├─ range-parser@1.2.0
├─ send@0.15.3
├─ serve-static@1.12.3
├─ setprototypeof@1.0.3
├─ statuses@1.3.1
├─ type-is@1.6.15
├─ unpipe@1.0.0
├─ utils-merge@1.0.0
└─ vary@1.1.1
Done in 30.42s.

El archivo packages.json se ha actualizado con express como dependencia instalando la versión 4.15.3.

{
  "name": "nspaces",
  "version": "0.1.0",
  "description": "El nuevo cuadro de mando en clave de ECMAScript",
  "main": "index.js",
  "author": "Javier Sanchez Toledano",
  "license": "MIT",
  "dependencies": {
    "express": "^4.15.3"
  }
}

Babel

El siguiente paso, un requisito indispensable para usar la versión 2015 de ECMAScript o ES6 es instalar el compilador Babel.

Babel convierte nuestro código en ES6 a una versión compatible con Node.js, pero es una dependencia de desarrollo. Una vez que esté lista una versión de producción, ahí no necesitamos Babel. Además del módulo babel vamos a emplear las especificaciones ES2015, que se encuentran en el paquete babel-preste-es2015. Ambos módulos se instalan con el indicador --dev,

$ yarn add --dev babel babel-preset-es2015

Ahora hay una nueva sección en nuestro archivo packages.json llamada devDependencies:

"devDependencies": {
  "babel-cli": "^6.24.1",
  "babel-preset-es2015": "^6.24.1"
}

Ahora vamos a crear un pequeño script para ejecutar nuestro archivo. En lugar de usar node, usaremos babel. Vamos a agregar la sección scripts a nuestro archivo con el siguiente contenido:

  "main": "src/index.js",
  "scripts": {
    "start": "babel-node src/index.js"
  },

Este script nos permite ejecutar yarn run start y ejecutar el guión indicado.

Por último, vamos a agregar una nueva sección para configurar el módulo Babel, quedando como sigue:

  "babel": {
    "presets": ["es2015"]
  }

Con estas configuraciones, estamos listos para continuar.

El ejemplo “Hola Mundo”

Ahora, como si fuera obligado, vamos a crear el ejemplo por excelencia en el mundo de la programación: el “Hola Mundo.

Vamos a crear un directorio src y dentro el archivo index.js. Este archivo será nuestro servidor Express y tendrá una sintaxis ES6, así que empezaremos importando el módulo express.

import express from 'express'

A continuación, creamos la aplicación:

let app = express()

Esta aplicación es un servidor web que se ejecuta localmente en el puerto 3000, así que vamos a indicarlo en una constante.

const PORT = 3000

Para este primer ejemplo usaremos una ruta comodín, indicada por el asterisco (*) y la función app.get(), es decir, cuando el verbo de la solicitud sea GET.

app.get('*', (req, res) => res.end('Hola Mundo'))

app.get() recibe dos parámetros, el primero es la ruta, en este caso es un comodín, lo que significa que todas las solicitudes GET serán atendidas por el según parámetro.

Este segundo parámetro es una función que recibe por su parte otros dos parámetros, el primero es una callback que contiene la solicitud, llamada req, del inglés request y el segundo parámetro, también es una callback llamada res de respuesta.

Ahora bien, lo que pasa dentro de esta función, es lo que se conoce como un flujo o stream que puede canalizarse de forma encadenada para controlarlo. Por ejemplo, se podría crear un flujo como este:

app.get('/ruta', (req, res) => {
  req.algo()
     .otraFuncion()
     .otraMas()
     .end()
}

Más adelante veremos esto a detalle. Por el momento, nuestra función es tan simple, que se resuelve en una línea.

Por último, activamos el servidor, escuchando el puerto indicado y con una pequeña función para informar que el servidor está funcionando.

app.listen(PORT, () => {
  console.log(`El servidor se está ejecuntando. Abre tu navegador en http://localhost:${PORT}/`)
})

Ahora, si ejecutamos el script con

$ yarn start

Veremos esta salida:

yarn start v0.24.5
$ babel-node src/index.js 
El servidor se está ejecuntando. Abre tu navegador en http://localhost:3000/

Y en el navegador, veremos la salida esperada:

$ http :3000
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 10
Date: Mon, 22 May 2017 00:39:49 GMT
X-Powered-By: Express

Hola Mundo

Así se ve el archivo completo del servidor:

'use strict'
import express from 'express'
let app = express()
const PORT = 3000

app.get('*', (req, res) =>  res.end('Hola Mundo'))
app.listen(PORT, () => {
  console.log(`El servidor se está ejecuntando. Abre tu navegador\
 en http://localhost:${PORT}/`)
})

Podemos hacer el ejemplo un poco más complejo, repitiendo el nombre que pasemos en la URL.

Vamos a crear una nueva ruta que será ubicada antes de la ruta comodín. Esta nueva ruta espera un nombre que dibujará en la respuesta. Veamos.

app.get('/name/:user', (req, res) => {
  res.status(200)
  res.set('Content-type', 'text/html')
  res.end(`
<html>
  <body>
    <h1>Hola ${req.params.user}</h1>
  </body>
</html>
  `)
})

Ahora, en la ruta /name/ debemos agregar un nombre, que se asignará a la variable usuario del objeto params en la solicitud req.

Vemos que el control de flujo es más complejo. Empezamos respondiendo que la respuesta es correcta, el estatus 200 es Ok. A continuación estallemos el tipo de datos que enviaremos con la respuesta, en este caso text/html.

Por último, con lo que cerramos el flujo, enviamos una pequeña página web, con el contenido de la variable req.params.user.

Veamos que pasa cuando llamamos esta nueva ruta.

$ http :3000/name/javier                                                                                                               
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 62
Content-type: text/html; charset=utf-8
Date: Mon, 22 May 2017 00:52:58 GMT
X-Powered-By: Express

<html>
  <body>
    <h1>Hola javier</h1>
  </body>
</html>

En el próximo artículo de la serie sobre Express, veremos como arrancar nuestro proyecto usando el generador express.


  1. Por eso se llaman intermediarios. 

Javier Sanchez Toledano

Auditor Líder ISO 9000 ● Desarrollo Web Full Stack ● Django/Python ● JavaScript · NodeJS · Angular · VueJS · EmberJS ● Swift 4 ● WordPress · Genesis Framework ● Lector ● Fotografo aficionado ● Generación X ● Soy de Tlaxcala

Tlaxcala, México

Comentarios