Servidor Express
Descripción
Montar un servidor web mediante paquetes propios de node
Objetivos
Entender la arquitectura de Express
Middleware
Uso de paquetes para extender la funcionalidad de Express
Creación de un servidor web que sirva:
Contenido estático
Contenido dinámico en base a templates
Content-type en JSON (para API posterior)
Empezamos proyecto
Documentación
Extensa pero concisa
Numerosos ejemplos
express
Instalar express mediante uno de los comandos siguientes:
npm install --save express@4.16.3 npm i -S express@4.16.3
Creamos el fichero server.js con el siguiente código:
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('Hola Mundo')
})
app.listen(3000)
Ejecución
Debería ejecutarse de cualquiera de las siguientes maneras:
npm start
node server.js
Utiliza nodemon para evitar reinicios al cambiar código
Prueba funcionamiento
Se echa de menos algún tipo de mensaje de arranque
Mira en la documentación como añadir esa opción
Cuando el método listen haya terminado...
Método listen
Permite añadir más parámetros
Un parámetro de tipo función (función de callback)
Es el único parámetro de este tipo, así los diferencia
app.listen([port[, host[, backlog]]][, callback])
app.listen(3000, () => {
console.log('Servidor web arrancado en el puerto 3000')
})
Añadir otra ruta
Utiliza el plugin ExpressSnippet de Visual Code para completado
Comprueba su funcionamiento con el app.listen
Datos nueva ruta:
URL: /contactar
Muestre el mensaje Página para contactar
Código ruta contactar
app.get('/contactar', (req, res) => {
res.send('Página para contactar')
})
Uso de JSON
Vamos a devolver un JSON en vez de un string:
app.get('/contactar', (req, res) => {
res.send({
nombre: 'pepito'
email: 'pepito@gmail.com'
})
})
Comprobar JSON
Utiliza algún plugin de formateo de JSON dentro del navegador
El JSON puede ser más complejo que el anterior, por ej:
https://api.arasaac.org/api/pictograms/es/search/casa
Comprueba como cambia el content type
Utiliza las herramientas de desarrollo
El cambio lo hace directamente Express

Los datos en JSON podrían estar:
En una variable
Incluso en otro fichero
Recibirse vía API
....
const contacto = require('./contacto.json')
app.get('/contactar', (req, res) => {
res.send(contacto)
})
Middleware
Son funciones que:
Se registran por express mediante app.use y se ejecutan en orden
Tienen acceso al objeto de solicitud (req), al objeto de respuesta (res) y a la siguiente función de middleware (next)
app.use((req, res, next)=>{
//operaciones del middleware
next() //para ir al siguiente middleware o a la ruta
// también podríamos hacer un send() y cortar
// la cola de middlewares, por ej en un control de permisos
})
Ejemplo de middleware
Podemos crear un middleware que guarde traza de las fechas de accesos
Para ver las propiedades que nos hacen falta podemos usar la API de Express
Es importante el orden
Entre los middlewares
Antes que las peticiones get, post....
var app = express()
app.use(function (req, res, next) {
var now = new Date().toString()
console.log(`Time: ${now} ${req.method} ${req.url}`)
next()
})
Logs a fichero
Completa el middleware anterior para que guarde los cambios en el fichero server.log
Piensa donde se debe poner el next() y si debes utilizar un método síncrono o asíncrono
Solución logs a fichero
app.use((req, res, next) => {
var now = new Date().toString()
var log = `${now}: ${req.method} ${req.url}`
console.log(log)
fs.appendFile('server.log', `${log}\n`, (err) => {
if (err) console.log(`No se ha podido usar el fichero de log: ${err}`)
})
next()
})
Más sobre logs
Podemos querer utilizar distintos transports o medios para logs
Ficheros
Consola
Distintos niveles (debug, err, warning...)
Distintos formatos de visualización (colores, negrita...)
Con posibilidad de ejecución de queries
....
Lo mejor es usar algún paquete que ya exista
Uso de contenido estático
Crea un fichero .html en la carpeta public
Ayúdate de emmet: ! + tab
Express ya tiene un middleware integrado para contenido estático
No deja de ser una función como las vistas anteriormente
No necesitamos importarla mediante un require
Una vez importado, hace un send() si existe el fichero, si no, un next()
Configuración express para contenido estático
const staticRoute = path.join(__dirname, 'public')
app.use(express.static(staticRoute))
__dirname es la raíz del proyecto
path.join para que sea multiplataforma
Podríamos configurar un directorio virtual (static para public)
const staticRoute = path.join(__dirname, 'public')
app.use('/static', express.static(staticRoute))
Template engine
Mostrar un index.html está bien pero puede que necesitemos:
Inyectar valores en el html
"includes" para footer, header... (patrón diseño DRY)
Tenemos que elegir un motor de plantillas
Utilizaremos hbs que es un wrapper de handlebars
Configuración de hbs
Instalación
npm i -S hbs
Configuración
// const hbs = require('hbs') app.set('view engine', 'hbs'); // clave valor
No hacemos un require porque no usamos ninguna función
express lo llama internamente
Indicamos a nodemon los tipos de ficheros a monitorizar (por defecto solo js):
"scripts": {
"start": "nodemon server.js -e js,hbs"
},
Uso de hbs
Definimos una carpeta views donde irán las templates
Fichero views/contactar.hbs:
...
<body>
<h1>{{pageTitle}}</h1>
<p>Aquí iría el formulario de contacto</p>
<footer>
<p>Copyright {{currentYear}}</p>
</footer>
</body>
....
Ejecutamos el método res.render() en vez de res.send()
Admite un objeto como segundo parámetro para pasar variables
app.get('/contactar', (req, res) => {
res.render('contactar.hbs', {
pageTitle: 'Contactar',
currentYear: new Date().getFullYear()
})
})
Partials mediante handlebars
Registramos el directorio donde se van a guardar:
const hbs = require('hbs')
hbs.registerPartials(path.join(__dirname, 'views', 'partials'))
app.set('view engine', 'hbs') // clave valor
Creamos fichero views/partials/footer.hbs:
<footer>
<p>Copyright {{getCurrentYear}}</p>
</footer>
Lo incluimos dentro de nuestro fichero views/contactar.hbs:
...
<body>
<h1>{{pageTitle}}</h1>
<p>Aquí iría el formulario de contacto</p>
{{> footer}}
<!-- con la linea anterior
tendríamos el footer mediante partials -->
</body>
....
Ejercicio templates
Añade una página de inicio además de contactar
Ambas deben cargar su correspondiente template que además cargará un partial para el header y otro para el footer
Uso de helpers
Se registran funciones que devuelven un código dinámico
Se pueden inyectar en cualquier template o partial.
hbs.registerHelper('getCurrentYear', () => new Date().getFullYear())
// con paso de parámetro:
hbs.registerHelper('toUpperCase', text => text.toUpperCase())
Podríamos eliminar el paso de currentYear a las vistas y utilizar el helper:
<footer>
<p>Copyright {{getCurrentYear}}</p>
<p>{{toUpperCase "Licencia MIT"}}</p>
{{>header}}
</footer>
¿Continuamos?
Ya estamos preparados para utilizar express para crear una API
Last updated
Was this helpful?