Cómo escribir middleware Express.js

C

 

Introducción

¿Alguna vez se ha preguntado qué está pasando con todo el middleware Express.js que está agregando a su aplicación web? En realidad, es bastante impresionante el tipo de funcionalidad que puede agregar a sus aplicaciones con solo una línea de código, o algunas:

// requires...

var app = express();

app.use("/static", express.static(__dirname + "/public"));
app.use(cookieParser('sekret'));
app.use(compress());

Las últimas tres líneas anteriores manejan gran parte de la funcionalidad de la aplicación web para nosotros. El primero app.use() llamada le dice a Express dónde se encuentran nuestros archivos estáticos y cómo exponerlos, el cookieParser('sekret') El middleware maneja todo el análisis de cookies (con encriptación), y el último gzip comprime automáticamente todos nuestros datos corporales HTTP. Nada mal por solo tres líneas de código.

Estos middleware son bastante típicos en su aplicación web promedio, pero puede encontrar algunos que hacen más que solo la compresión de datos estándar o el análisis de cookies. Tome estos, por ejemplo:

  • casco: Ayuda a proteger su aplicación mediante la configuración de varios encabezados HTTP
  • express-simple-cdn: Utilice fácilmente una CDN para sus activos estáticos
  • unirse-io: Unir archivos sobre la marcha para reducir el recuento de solicitudes HTTP
  • pasaporte: agrega autenticación de usuario a las rutas seleccionadas

Y aquí es una lista mucho más amplia de middleware que quizás desee utilizar.

Ahora que ha visto algunos ejemplos, aquí encontrará todo lo que puede hacer con él:

  • Ejecute cualquier código, incluido el código asincrónico
  • Realizar cambios o adiciones a los objetos de solicitud y respuesta
  • Finalizar el ciclo de solicitud-respuesta
  • Llame al siguiente middleware de la pila

Con las infinitas posibilidades, estoy seguro de que tiene algunas ideas propias que le gustaría crear, por lo que a lo largo del resto de este artículo le mostraré cómo escribir su propio middleware. Hay algunos tipos diferentes de middleware que puede escribir (aplicación, enrutador, manejo de errores, etc.), pero en este artículo nos centraremos solo en el nivel de la aplicación.

Los basicos

Se puede pensar en middleware casi como si fuera una ruta Express. Toman los mismos parámetros y todo, pero a diferencia de las rutas normales, no es necesario que proporciones una ruta URL para el middleware. Las dos mayores diferencias son cómo se trata la ruta y cuándo se llama.

La ruta proporcionada se trata como un prefijo, por lo que si tiene algo como app.use('/api', ...), entonces su middleware se ejecutará si /api se llama y si /api/users se llama. Esto es diferente de las rutas en las que la ruta debe coincidir exactamente.

La ruta URL se puede omitir de la app.use() llame si desea que su código se ejecute para todas las solicitudes; de lo contrario, puede especificar una ruta y hacer que su código solo se ejecute cuando se solicite esa ruta (y todas sus subrutas). Por ejemplo, esto podría ser útil para agregar autenticación solo a unas pocas rutas determinadas.

Un middleware simple podría verse así:

var app = express();

app.use(function(req, res, next) {
  console.log('Called URL:', req.url);
  next();
});

Mientras que un controlador de ruta se ve así:

var app = express();
 
app.get("https://Pharos.sh.com/", function(req, res, next) {
  res.send('Hey there...');
});

¿Ver? Básicamente son lo mismo, por lo que escribir estas funciones debería resultarle bastante familiar.

Los parámetros utilizados son:

  • req: Un objeto que contiene toda la información de solicitud relevante. Esto podría ser cualquier cosa, desde la URL solicitada hasta el cuerpo de una solicitud POST hasta la dirección IP del usuario.
  • res: Este es el objeto de respuesta, que se utiliza para enviar datos al usuario para la solicitud dada. Puede usar esto para enviar un código de respuesta HTTP 404 o para enviar HTML renderizado a través de res.render().
  • next: Y finalmente, el next El parámetro es una devolución de llamada para decirle a Express cuando nuestro middleware ha terminado. Si realiza cualquier IO (como llamadas a la base de datos) o un cálculo pesado, es probable que deba hacer que la función sea asíncrona para evitar bloquear el hilo de ejecución principal, en cuyo caso tendrá que usar next.

Vale la pena señalar que si su middleware no finaliza el ciclo de solicitud-respuesta con res.end(...) entonces tú debe llamada next() para pasar el control al siguiente middleware. Si no lo hace, la solicitud quedará pendiente y expirará.

Un ejemplo

En este ejemplo, crearemos un middleware que le ayudará a traducir automáticamente texto entre idiomas. Sin embargo, este no es un módulo i18n típico, usaremos Google Translate en su lugar.

Supongamos que ha creado una aplicación de chat que le permite hablar con personas de todo el mundo y, para hacerlo sin problemas, necesita que el texto se traduzca automáticamente. En este caso de uso, la mayoría de los módulos i18n no funcionarían ya que necesita pretraducir todas las cadenas, lo que no podemos hacer ya que estamos tratando con la entrada del usuario.

Claro, puede manejar la traducción en cada una de sus rutas Express, o puede manejarla por usted en middleware, lo que mantiene su código de ruta más limpio y evita que se olvide de agregar la traducción a cada ruta que lo necesite.

Las cadenas (mensajes de usuario) ingresan a través de una API REST, por lo que tendremos que verificar todos los cuerpos de las rutas de la API en busca de texto para traducir. Todas las cadenas que se guardan en la base de datos en las llamadas POST se mantendrán en sus idiomas nativos, pero todas las cadenas que se recuperen de la base de datos con llamadas GET se traducirán al idioma especificado en el encabezado HTTP Accept-Language que acompaña a la solicitud del usuario.

Pensé que no haríamos todos los mensajes de la base de datos en el mismo idioma, ya que luego tendríamos que traducir algunos de ellos dos veces, lo cual degrada la calidad de la traducción.

En primer lugar, escribamos una función simple para llamar a la API de Google Translate:

var googleTranslate = require('google-translate')('YOUR-API-KEY');

var translate = function(text, lang, cb) {
	googleTranslate.translate(text, lang, function(err, translation) {
		if (!translation) cb(err, null);
		cb(err, translation.translatedText);
	});
}

Luego usaremos esa función en nuestro código de middleware, que se exporta en modules.export para su uso por la aplicación.

module.exports = function(req, res, next) {
	if (req.method === 'GET') {
		var lang = 'en';
		var langs = req.acceptsLanguages();
		if (langs[0] !== '*') {
			if (langs[0].length > 2) {
				// ex: en-US
				lang = langs[0].substring(0, 2);
			} else {
				// ex: en
				lang = langs[0];
			}
		}

		if (lang !== res.body.lang) {
			return translate(res.body.message, lang, function(err, translation) {
				res.body.message = translation;
				res.body.lang = lang;
				next();
			});
		}
	}

	next();
};

NOTA: No es así como se modifica un Response cuerpo. Solo lo estoy simplificando en aras de la brevedad. Si desea ver cómo modificar realmente el cuerpo, consulte el compresión middleware, que lo hace correctamente. Tienes que proxy res.write y res.end funciones, que no hice porque solo sería una distracción de los conceptos que estoy tratando de mostrar aquí.

Y finalmente, aplicamos el middleware a nuestra aplicación. Solo asegúrate de llamar al app.use funcionará después de haber declarado sus rutas. El orden en el que se llama es el orden en que se ejecuta cada función.

Además, asegúrese de llamar next() en cada uno de tus /api rutas, de lo contrario, el middleware no se ejecutará.

var expressGoogleTranslate = require('my-translation-middleware');

var app = express();

app.get('/api/message', function(req, res, next) {...});
app.get('/api/message/all', function(req, res, next) {...});
app.post('/api/message', function(req, res, next) {...});
app.delete('/api/message/id', function(req, res, next) {...});

app.use('/api', expressGoogleTranslate);

Y eso es todo lo que hay que hacer. Cualquier cadena devuelta en el Response El cuerpo que sea un idioma diferente al que acepta el usuario será traducido por Google Translate, que detecta en qué idioma está el texto de origen.

Entonces, si nuestra respuesta comenzó con este aspecto …

{
	"message": "The quick brown fox jumps over the lazy dog"
	"lang": "en"
}

… y el usuario solo acepta Swahili, luego de que se ejecute el middleware obtendremos una traducción final que se ve así:


{
	"message": "Haraka kahawia mbweha anaruka juu ya mbwa wavivu"
	"lang": "sw"
}

Conclusión

Aunque pueda parecer intimidante, el middleware es realmente fácil de crear en Express. Puede usarlo para casi cualquier cosa, sin importar cuán simple o complejo sea.

Solo asegúrese de hacer una búsqueda rápida en npm para lo que sea que esté tratando de hacer, ya que ya hay toneladas de código. Estoy seguro de que ya hay un paquete que hace lo que hace mi código de traducción (y probablemente también mucho mejor).

¿Tiene alguna idea para crear middleware o cómo mejorar mi ejemplo anterior? ¡Háznoslo saber en los comentarios!

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con tus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad