Miguel Castillo - 15 May 2020
Decorators - Fastify desde 0
Supongamos que en algún hook como preHanlder
o preValidation
quieres agregar algún campo que puedas utilizar
en las siguientes funciones del ciclo de vida, algo común por ejemplo guardar datos del usuario autenticado.
Este es un ejemplo erroneo.
server.get("/books", {// Recuerda que con async ya no necesitamos donepreHandler: async (request, reply) => {try {// Obtenemos el token enviado en las cabecerasconst token = request.headers["authorization"];// Vamos a simular que obtenemos datos a partir del tokenconst userData = await getUserData(token);// MAL xrequest.user = userData.name;return;} catch (error) {return reply.code(400).send({ error: "No se pudo obtener datos del usuario" });}},handler: (request, reply) => {reply({books: ["100 años de soledad", "La metamorfosis"],user: request.user,});},});
La forma correcta de agregar campos extra tanto al request, al reply y a toda nuestra instancia es mediante los decorators. La forma correcta de hacer el ejemplo anterior sería la siguiente:
// Antes de las rutas definimos el decoratorserver.decorateRequest("user", "");server.get("/books", {// Recuerda que con async ya no necesitamos donepreHandler: async (request, reply) => {try {// Obtenemos el token enviado en las cabecerasconst token = request.headers["authorization"];// Vamos a simular que obtenemos datos a partir del tokenconst userData = await getUserData(token);// Con el decorator ahora esto si es correctorequest.user = userData.name;return;} catch (error) {return reply.code(400).send({ error: "No se pudo obtener datos del usuario" });}},handler: (request, reply) => {reply.send({books: ["100 años de soledad", "La metamorfosis"],user: request.user,});},});
Nota: En el demo simulamos getUserData
como una promesa.
¿Para qué sirven los decorators?
Los decorators permiten agregar campos adicionales a nuestro request
, reply
o server
sin afectar la optimización llevada a cabo
por Fastify, el uso más común de los decorators es al momento de utilizar los plugins
de Fastify para
agregar nuevas funcionalidades dentro de todas nuestras rutas, por ejemplo el plugin fastify-cookie
nos
genera decorators para asignar cookies, obtener valos de una cookie y eliminar cookies en todas nuestras rutas.
Decorator de request
Podemos agregar propiedades y funcionalidades extra al request utilizando decorateRequest
:
const server = fastify();server.decorateRequest("user", "");
Para comprobar si existe el decorator utilizamos hasRequestDecorator
:
const server = fastify();server.decorateRequest("user", "");server.hasDecorator("user");
Decorator de reply
Podemos agregar propiedades y funcionalidades extra al request utilizando decorateReply
:
const server = fastify();server.decorateReply("replyUtil", "");
Para comprobar si existe el decorator utilizamos hasReplyDecorator
:
const server = fastify();server.decorateReply("replyUtil", "");server.hasReplyDecorator("replyUtil");
Nota acerca de los decorator
No se puede definir más de una vez el mismo decorator, esto provocará automaticamente que la aplicación mande un error, sin embargo si se define un nuevo contexto de Fastify, dentro de ese contexto se pueden definir decorators con el mismo nombre, veremos esto más a detalle en la lección de plugins.
Decorators en la práctica
El siguiente fragmento de código muestra una parte del plugin de cookies de Fastify:
// Fragmento de plugin.js en fastify-cookie, línea 53fastify.decorateRequest("cookies", {});fastify.decorateReply("setCookie", function setCookieWrapper(name,value,options) {return fastifyCookieSetCookie(this, name, value, options, secret);});fastify.decorateReply("clearCookie", function clearCookieWrapper(name,options) {return fastifyCookieClearCookie(this, name, options);});
Lo que hace el plugin de cookies es declarar decoradores con valores guardados o con funciones que se van
a ejecutar. Al configurar este plugin
tendremos disponibles aquellos métodos en nuestro reply
y request
.
server.get("/logout", (request, reply) => {// Ahora tengo disponible mediante el hook de cookies las cookies enviadas en la cabecera httpconst myCookies = request.cookies;// Voy a simular eliminar la cookieSession como un cierre de sesión, el decorator declarado en// el plugin me permite hacer estoreply.code(200).clearCookie("cookieSession").send({ message: "Sesión cerrada" });});