Radiografía del proyecto Express
Después de haber generado el proyecto y la refactorización para usar la sintaxis de ES6 y Babel, vamos a revisar los archivos que componen el proyecto y tratar de comprender el papel que cada uno de ellos juega en el proyecto.
El archivo bin/server.js
Este es el archivo que arranca el servidor cuando lo llamamos desde el script de arranque. Debido a las funciones de apoyo que utiliza, el arranque del servidor aparece al final.
const port = normalizarPuerto(process.env.PORT || '3000')
app.set('port', port)
const server = http.createServer(app)
server.listen(port)
server.on('error', siHayError)
server.on('listening', alEscuchar)
const port = normalizarPuerto(process.env.PORT || '3000')
La primera línea crea la constante port
. El valor lo toma
de la variable de entorno PORT
si existe, o lo establece
como el 3000 por omisión.
app.set('port', port)
La segunda línea usa el método .set()
para almacenar
el valor del puerto en la tabla de propiedades de app
, el
problema es que no veo que se use este valor en ningún lado.
No hay ningún app.get('port')
. Pero bueno, después puedo
eliminar la constante y usar solo el getter.
const server = http.createServer(app)
Luego creamos un servidor, usando el método
http.createServer(app)
. Este método pertenece al núcleo de
Node.js y recibe como parámetro opcional un escuchador
de solicitudes (requestListener
) que automáticamente se
agrega al request o solicitud.
Este método devuelve una nueva instancia de
http.Server
que colocamos en la constante server
.
server.listen(port)
El método listen()
pertenece a http
, pero lleva en la
solicitud la aplicación de Express.js. No me queda claro
por qué damos este rodeo, si según la documentación del
método app.listen()
podemos usar como un atajo.
Sospecho que tiene que ver con el módulo Debug
, pero más
adelante veremos como usar solo app
.
Ya investigué y resulta que
http
proporciona algunos métodos que no proporcionaexpress
. Y dado que Express.js es mucho más que un servidor HTTP, delega estas funciones al vulgar y corriente módulohttp
. El creador del servido, explica en un caso en GitHub porque no es necesario.
En este momento, es cuando arranca el servidor e inicia el Node Event Loop o ciclo de eventos de Node.js que es lo que permite a nuestro proyecto que maneje múltiples operaciones tras bambalinas. El event loop es un concepto muy importante que revisaremos a fondo próximamente.
Una vez que ha arrancado el servidor, activamos dos monitores, uno de ellos para el manejo de errores y otro para monitorear el arranque:
server.on('error', siHayError)
server.on('listening', alEscuchar)
El primer monitor, escucha el evento 'error'
y cuando sucede lanza la función siHayError
que veremos a continuación:
let siHayError = (error) => {
if (error.syscall !== 'listen') throw error
let bind = typeof port === 'string' ? `Pipe ${port}` : `Puerto ${port}`
// manejamos los errores con mensajes amigables
switch (error.code) {
case 'EACCES':
console.error(`${bind} requiere de mayores privilegios`)
process.exit(1)
break
case 'EADDRINUSE':
console.error(`El ${bind} ya está en uso`)
process.exit(1)
break
default:
throw error
}
}
Veamos como funciona.
if (error.syscall !== 'listen') throw error
En la primera línea verifica si el error no es de escucha en cuyo caso, lanza el error al sistema.
`let bind = typeof port === 'string' ? `Pipe ${port}` : `Puerto ${port}`
Esta línea verifica si estamos mandado un número de puerto o un control de flujo o pipe. Si es un texto, es un pipe, sino, es un puerto.
Lo siguiente es un bloque de elección. Si el error es tipo EACCES
significa que no tenemos permisos para usar ese puerto, por ejemplo el 80
. Si la dirección ya está en uso, el error sería EADDRINUSE
. De nuevo, este monitor solo busca errores al iniciar el servidor.
Si el error no es alguno de esto, lo lanza sin procesar.
El siguiente monitor nos indica si el servidor está escuchando el puerto indicado.
let alEscuchar = () => {
let address = server.address()
let bind = typeof add === 'string' ? `el pipe ${address}` : `el puerto ${address.port}`
debug(`Escuchando en ${bind}`)
}
Verifica la dirección y el puerto del objeto que pasa el servidor, igual que la función bind
del monitor anterior, determina si estamos usando un puerto o un control de flujo.
Estos dos monitores usan la función debug
que busca que esté presente en las variables de entorno la clave DEBUG
con el valor aspases:server
.
El archivo app.js
Este es el archivo del servidor Express.js propiamente dicho. Las primeras líneas sirven para importar los módulos que ocuparemos en el proyecto.
Luego cargamos las rutas y preparamos la aplicación app
. Configuramos el motor de plantillas. Primero el directorio y luego el tipo específico.
A continuación, cargamos los módulos en la aplicación. El que carga el favicon, la bitácora, el analizador de contenido y de cookies, el preprocesador de estilos y por último, las rutas.
Una pequeña funciono para capturar las solicitudes de páginas no encontradas. Y otra para los errores 500, que solo se muestra si estamos ejecutando el servidor con la bandera de development
.
Los archivos de rutas
Los archivos de rutas no son la gran cosa. El índice llama a la plantilla index
y le pasa en el contexto la variable title
.
La ruta /users
solo imprime un mensaje dummy.
Las plantillas
La plantilla base o layout.hbs
es una página web mínima, con una variable {{ title }}
y un bloque {{{ body }}}
.
La plantilla index
se dibuja sobre el bloque body
y solo imprime la variable title
. La plantilla error hace lo mismo, pero con el mensaje de error.
Esto es todo lo que hace el proyecto generado por la CLI de Express.js y refactorizado para convertirlo con Babel en ES6.
Ahora si estamos listos para empezar con algo más serio.