Cómo manejar la carga de archivos en Node.js con Fastify
Amarachi Aso
8 de diciembre de 2022
0 minutos de lecturaLa carga de archivos es una funcionalidad común en las aplicaciones web. Por eso, muchos frameworks web ofrecen formas para que las aplicaciones del lado del servidor acepten archivos y trabajen con ellos. Este es el caso de Fastify, un framework web para Node.js que suele considerarse el sucesor de Express. Es rápido y se enfoca en ofrecer la mejor experiencia para desarrolladores, con una potente arquitectura de plugins y la menor sobrecarga posible.
En este tutorial, usarás el framework Fastify en una aplicación Node.js para configurar la carga de archivos. Aprenderás cómo funcionan las cargas de archivos en un servidor típico y cómo manejarlas en una aplicación de servidor Fastify.
Conceptos básicos de la carga de archivos
Si quieres cargar archivos en un servidor de aplicaciones, una computadora cliente debe enviar una solicitud POST al servidor. En el cuerpo de la solicitud, enviará datos que normalmente se envían mediante formularios HTML. Los formularios HTML ofrecen tres métodos para codificar datos:
application/x-www-form-urlencoded(predeterminado) es el tipo de contenido o la codificación predeterminados de los formularios HTML. Sin embargo, cuando se envían archivos mediante este formulario, se deben codificar con el métodomultipart/form-data.multipart/form-datase usa para representar las distintas partes o campos de un formulario HTML. Las partes se envían como pares de nombre y valor en el cuerpo de la solicitud. El nombre y el valor de cada par corresponden, respectivamente, al nombre y al valor de los campos de entrada.text/plainse usa para enviar datos en texto sin formato y no permite enviar archivos.
Cuando se envían archivos a un servidor de aplicaciones, el objetivo suele ser que el servidor los procese, los guarde o haga ambas cosas. Las aplicaciones de servidor pueden procesar y guardar los archivos cargados de varias maneras, entre ellas:
Guardarlos en el sistema de archivos de tu propio servidor. Puede ser en un directorio dedicado del mismo servidor donde se ejecuta tu aplicación o en otro servidor dedicado al almacenamiento de archivos.
Guardarlos en una base de datos.
Cargar los archivos en un servicio de almacenamiento en la nube, como Amazon S3 o Cloudinary.
Este tutorial se centra en el primer método para manejar las cargas de archivos.
Cómo implementar la carga de archivos con Fastify
Antes de comenzar este tutorial, necesitarás lo siguiente:
Node.js instalado
Un editor de código de tu elección, como Visual Studio Code (VS Code)
Postman. Puedes iniciar sesión y usar la aplicación web o instalarla en tu computadora.
En las siguientes secciones, crearás un proyecto Fastify, configurarás un plugin para cargar archivos, crearás una ruta /upload que pueda manejar varias cargas de archivos y escribirás un caso de prueba para la ruta.
Crea un proyecto y configura Fastify
Para comenzar, debes crear un proyecto y configurar Fastify. Ve al directorio donde quieras crear el proyecto y crea una carpeta llamada fastify-file-upload. En la terminal, ejecuta este comando:
Cambia el directorio actual a esta carpeta:
Luego, abre la carpeta en tu editor de código preferido. Si usas VS Code, puedes ejecutar este comando:
Inicializa el proyecto y crea un archivo package.json ejecutando lo siguiente:
Luego, instala las dependencias que usarás en este proyecto:
Y crea dos archivos: app.js y server.js:
app.js contendrá el código de tu aplicación. Copia y pega en él el siguiente código:
import Fastify from fastify
Este código importa el framework Fastify y crea una instancia de una aplicación a partir de él. Luego, agrega el siguiente código al archivo server.js:
Este código ejecutará tu aplicación cuando la inicies o devolverá un error si ocurre algún problema al hacerlo.
En este proyecto, usarás la sintaxis de módulos ES6; por lo tanto, tus archivos JavaScript deben cargarse como módulos. Para asegurarte de que se carguen como módulos, agrega la propiedad type a tu archivo package.json y asigna el valor module:
Configura un plugin para cargar archivos
Fastify-multipart ofrece compatibilidad con tipos de contenido multipart en Fastify. Como ya instalaste el plugin junto con las dependencias, es hora de configurarlo. Para ello, importa multipart desde '@fastify/multipart' y luego regístralo.
Agrega las líneas que comienzan con + al contenido de tu archivo app.js:
Aquí registraste multipart en la aplicación Fastify que creaste antes. Ahora, la instancia de tu aplicación puede analizar fácilmente el tipo de contenido multipart.
Carga de archivos
Hay varias formas de acceder a los archivos de una solicitud POST. Por ejemplo, si sabes que una solicitud contiene un solo archivo, puedes acceder a él con el siguiente código:
En este código, request es el parámetro de solicitud de la función controladora de tu ruta de carga. La función controladora se vería más o menos así:
Si esperas varios archivos, la diferencia es que llamarías al método files() en lugar de file(), así:
En tu archivo app.js, debes escribir código para implementar por completo la carga de varios archivos. Pero primero, crea un directorio donde se guardarán los archivos cargados en tu aplicación. Crea este directorio en la raíz del proyecto y llámalo uploads:
Después, haz las siguientes modificaciones en el archivo app.js:
En el código modificado, importaste funciones de los módulos principales de Node.js fs, util y stream. Luego, creaste una ruta /upload y su función controladora.
Dentro de la función controladora, usaste req.files() para acceder a todos los archivos de la solicitud. Recorriste los archivos y, para cada uno, el código await pump(part.file, fs.createWriteStream(`./uploads/${part.filename}`)) lo carga y lo guarda en el directorio de cargas que creaste antes.
Ten en cuenta que los archivos que cargas no se acumulan en la memoria antes de guardarse. En su lugar, se usa la función fs.createWriteStream para crear un flujo en el extremo receptor, mientras que el flujo de archivo que proviene de part.file se envía al flujo recién creado. Esto garantiza que el contenido del archivo no se almacene primero en un búfer en la memoria; en cambio, los fragmentos de datos se escriben directamente en el archivo a medida que llegan por el flujo. Esto es especialmente útil para cargar archivos grandes. No bloquea el bucle de eventos y, además, permite manejar archivos en tu aplicación con un uso eficiente de la memoria.
Ahora es momento de iniciar el servidor y enviarle archivos con Postman. En tu archivo package.json, reemplaza el script de inicio por el siguiente:
Luego, inicia el servidor con este comando:
Ve a Postman y envía una solicitud POST a http://localhost:8000/upload. En el cuerpo de la solicitud que vas a enviar, selecciona la opción form-data y carga dos archivos de tu elección:

Aquí, cargas un archivo llamado article.txt y otro llamado cover.jpg (sus claves serán «article» y «coverImage», respectivamente). Después de cargar los archivos, deberías obtener el código de estado 200 y el objeto de respuesta {message : 'files uploaded' }:

También deberías ver los archivos agregados al directorio «upload» que creaste antes para las cargas.
En este punto, ya manejaste correctamente la carga de varios archivos con el plugin fastify/multipart. La mayoría de los formularios requieren que proporciones no solo archivos, sino también otros campos de texto. Para manejar este tipo de formularios, debes modificar el código existente para procesar tanto los flujos de archivos como los demás campos.
Para hacerlo, modifica tu archivo app.js de la siguiente manera:
Observa que esta vez usas req.parts() para acceder tanto a los flujos de archivos como a los campos, en lugar de req.files(). Además, en el cuerpo del bucle, usas una instrucción if para determinar qué parte es un archivo y manejarla de forma distinta a los campos.
Ahora es momento de enviar otra solicitud. Guarda el archivo y luego detén y reinicia el servidor con npm start. Vuelve a Postman, elimina los pares clave/valor de la solicitud anterior y crea otros nuevos. En el primer campo, escribe tu nombre completo y luego agrega dos archivos cualesquiera, como antes.
Nota: Si vas a usar los mismos archivos, quizá quieras eliminar los que cargaste la última vez del directorio de cargas.
Tu solicitud debería verse así:

Si es así, tu aplicación ya puede manejar varios flujos de archivos y campos.
Escribe casos de prueba
Para proteger la implementación de carga de archivos, debes escribir pruebas. Pero ¿cómo puedes escribir casos de prueba para la carga de archivos en Fastify? En este caso, usarás el framework de pruebas tap, el paquete form-auto-content y el método .inject de Fastify para escribir los casos de prueba.
Crea el archivo app.test.js en la raíz del proyecto. Luego, copia y pega en él el siguiente código:
Reemplaza las rutas ./sample_files/file.txt y ./sample_files/cover.jpg por las rutas de dos archivos cualesquiera de tu sistema de archivos. También puedes obtener una copia de estos archivos aquí.
El método .inject de Fastify te permite inyectar solicitudes HTTP ficticias en tu aplicación sin ejecutar el código en un servidor real. En el código anterior, observa cómo usaste formAutoContent para crear un formulario llamado myForm y luego lo usaste como cuerpo de la solicitud en una solicitud POST ficticia dentro del caso de prueba. Solo tienes un caso de prueba, que espera que, al enviar un formulario con varios archivos, la aplicación devuelva un statusCode de 200.
Ejecuta esta prueba y confirma que pase. En tu archivo package.json, reemplaza el script de prueba por este:
Luego, ejecuta lo siguiente:
La prueba debería pasar y el resultado debería verse así:

Todo el código de este tutorial está disponible en este repositorio de GitHub.
Conclusión
En este artículo, aprendiste los conceptos básicos de la carga de archivos y por qué los formularios que contienen archivos solo se codifican con el multipart/form-data content-type. También aprendiste las dos formas en que las aplicaciones de servidor pueden procesar y guardar archivos: en un directorio dedicado del mismo servidor o en un servicio de almacenamiento en la nube, como Amazon S3. Después, aprendiste a manejar cargas en Fastify, un framework web rápido y ligero para Node.js.
Si quieres aprender más, consulta la documentación del plugin Fastify-multipart y la guía de Fastify sobre pruebas.



