C贸mo escribir middleware Express.js

     

    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!

     

    Etiquetas:

    Deja una respuesta

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