Escribiendo middleware para usar en aplicaciones Express

Resumen

Las funciones de middleware son funciones que tienen acceso al objeto request (req), el objeto de respuesta (res), y la función next en el ciclo solicitud-respuesta de la aplicación. La función next es una función en el router Express que, al ser invocada, ejecuta el middleware que sucede al middleware actual.

Las funciones del middleware pueden realizar las siguientes tareas:

  • Ejecutar cualquier código.
  • Hacer cambios en los objetos de petición y respuesta.
  • Finalizar el ciclo petición-respuesta.
  • Llamar al siguiente middleware de la pila.
    • Si la función middleware actual no finaliza el ciclo petición-respuesta, debe llamar a next() para pasar el control a la siguiente función middleware. En caso contrario, la petición quedará colgada.

      La siguiente figura muestra los elementos de una llamada a una función middleware:

      Método HTTP para el que se aplica la función middleware.

      Ruta para la que se aplica la función de middleware.
      La función de middleware.
      Argumento de devolución de la función de middleware, llamado «next» por convención.
      Argumento de respuesta HTTP a la función middleware, llamado «res» por convención.
      Argumento de solicitud HTTP a la función middleware, llamado «req» por convención.

      A partir de Express 5, las funciones de middleware que devuelven una Promise llamarán a next(value) cuando rechacen o lancen un error. next será llamado con el valor rechazado o con el error lanzado.

      Ejemplo

      Aquí hay un ejemplo de una simple aplicación Express «Hello World».El resto de este artículo definirá y añadirá tres funciones de middleware a la aplicación: una llamada myLogger que imprime un simple mensaje de registro, una llamada requestTime que muestra la marca de tiempo de la petición HTTP, y una llamada validateCookies que valida las cookies entrantes.

var express = require('express')var app = express()app.get('/', function (req, res) { res.send('Hello World!')})app.listen(3000)

Función middleware myLogger

Aquí tienes un ejemplo sencillo de una función middleware llamada «myLogger». Esta función sólo imprime «LOGGED» cuando una petición a la app pasa por ella. La función middleware se asigna a una variable llamada myLogger.

var myLogger = function (req, res, next) { console.log('LOGGED') next()}

Nota la llamada anterior a next(). Al llamar a esta función se invoca la siguiente función de middleware en la app.La función next() no forma parte de la API de Node.js o Express, sino que es el tercer argumento que se pasa a la función de middleware. La función next() podría llamarse de cualquier manera, pero por convención siempre se llama «next».Para evitar confusiones, utiliza siempre esta convención.

Para cargar la función middleware, llama a app.use(), especificando la función middleware.Por ejemplo, el siguiente código carga la función de middleware myLogger antes de la ruta a la ruta raíz (/).

var express = require('express')var app = express()var myLogger = function (req, res, next) { console.log('LOGGED') next()}app.use(myLogger)app.get('/', function (req, res) { res.send('Hello World!')})app.listen(3000)

Cada vez que la app recibe una petición, imprime el mensaje «LOGGED» en el terminal.

El orden de carga del middleware es importante: las funciones de middleware que se cargan primero también se ejecutan primero.

Si myLogger se carga después de la ruta a la ruta raíz, la petición nunca llega a ella y la app no imprime «LOGGED», porque el manejador de ruta de la ruta raíz termina el ciclo petición-respuesta.

La función de middleware myLogger simplemente imprime un mensaje, y luego pasa la petición a la siguiente función de middleware en la pila llamando a la función next().

Función middleware requestTime

A continuación, crearemos una función middleware llamada «requestTime» y añadiremos una propiedad llamada requestTimeal objeto request.

var requestTime = function (req, res, next) { req.requestTime = Date.now() next()}

La app ahora utiliza la función de middleware requestTime. Además, la función callback de la ruta raíz utiliza la propiedad que la función middleware añade a req (el objeto de la petición).

var express = require('express')var app = express()var requestTime = function (req, res, next) { req.requestTime = Date.now() next()}app.use(requestTime)app.get('/', function (req, res) { var responseText = 'Hello World!<br>' responseText += '<small>Requested at: ' + req.requestTime + '</small>' res.send(responseText)})app.listen(3000)

Cuando haces una petición a la raíz de la app, ésta ahora muestra la marca de tiempo de tu petición en el navegador.

Función middleware validateCookies

Por último, crearemos una función middleware que valide las cookies entrantes y envíe una respuesta 400 si las cookies no son válidas.

Aquí tenemos una función de ejemplo que valida las cookies con un servicio asíncrono externo.

async function cookieValidator (cookies) { try { await externallyValidateCookie(cookies.testCookie) } catch { throw new Error('Invalid cookies') }}

Aquí utilizamos el cookie-parser middleware para analizar las cookies entrantes del objeto req y pasarlas a nuestra función cookieValidator. El validateCookies middleware devuelve una Promise que al ser rechazada activará automáticamente nuestro manejador de errores.

var express = require('express')var cookieParser = require('cookie-parser')var cookieValidator = require('./cookieValidator')var app = express()async function validateCookies (req, res, next) { await cookieValidator(req.cookies) next()}app.use(cookieParser())app.use(validateCookies)// error handlerapp.use(function (err, req, res, next) { res.status(400).send(err.message)})app.listen(3000)

Nota cómo next() se llama después de await cookieValidator(req.cookies). Esto asegura que si cookieValidator se resuelve, se llamará al siguiente middleware de la pila. Si pasas cualquier cosa a la función next() (excepto la cadena 'route' o 'router'), Express considera que la petición actual es un error y se saltará cualquier función restante de enrutamiento y middleware que no sea de gestión de errores.

Debido a que tienes acceso al objeto de solicitud, al objeto de respuesta, a la siguiente función de middleware en la pila y a toda la API de Node.js, las posibilidades con las funciones de middleware son infinitas.

Para más información sobre el middleware de Express, consulta: Usando el middleware Express.

Middleware configurable

Si necesitas que tu middleware sea configurable, exporta una función que acepte un objeto de opciones u otros parámetros, la cual, devuelve la implementación del middleware basada en los parámetros de entrada.

Archivo: my-middleware.js

module.exports = function (options) { return function (req, res, next) { // Implement the middleware function based on the options object next() }}

El middleware ahora puede ser utilizado como se muestra a continuación.

var mw = require('./my-middleware.js')app.use(mw({ option1: '1', option2: '2' }))

Referirse a cookie-session y compresión para ejemplos de middleware configurable.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *