Realiza un CRUD en MySQL con Node.js
Durante el desarrollo de una aplicación robusta en la que interactuamos con bases de datos, es seguro que el desarrollador backend realizará las cuatro operaciones básicas de creación, lectura, actualización y eliminación.
Conocido como CRUD (abreviatura en inglés de las palabras Create, Read, Update y Delete), este conjunto de operaciones de base de datos es crucial para un programador y, dada su importancia, decidí crear un paso a paso sobre cómo realizar estas cuatro acciones con Node.js y MySQL2.
¿Qué son Node.js y MySQL?
Para el desarrollo de esta aplicación utilizaremos Node.js y MySQL. Ambos interactúan muy bien entre sí, pero cada uno tiene su propia área de actividad: mientras Node es un intérprete de JavaScript que da soporte a este lenguaje tanto del lado del cliente como del lado del servidor, MySQL es un sistema de gestión de bases de datos que utiliza el lenguaje SQL de la empresa Oracle, siendo muy utilizado para esta funcionalidad en la actualidad.
Instalando lo esencial para el desarrollo
Vamos a iniciar nuestro proyecto creando un directorio contentivo del archivo package.json. También instalaremos MySQL2 (utilizado para la conexión entre Node.js y MySQL), Express (para organización de requisiciones y respuestas) y Nodemon (para evitar la necesidad de reiniciar el servidor cada vez que hiciéramos algún cambio en los archivos del proyecto). Para esto, basta ejecutar los siguientes comandos en la terminal iniciada en la carpeta raíz del proyecto:
npm init -y
npm install mysql2
npm install express
npm install nodemon
Inicializando o servidor
Necesitamos crear un archivo que se encargará de inicializar nuestro servidor Node. Luego crearemos una carpeta llamada src con un archivo app.js dentro:
Explicando mejor lo que se hizo en el código de la figura 2, tenemos:
- Importación de Express en la línea 1 y ejecución como una constante en la línea 3;
- La declaración en la línea 5 para la aplicación de que las solicitudes y respuestas se utilizarán en formato Express con JSON;
- El uso de la función de escucha en la línea 9 que recibe como parámetros un puerto en el que trabajará el servidor (puedes usar cualquier puerto que esté libre) y una función que, en nuestro caso, muestra un mensaje en la pantalla del puerto en uso.
Para inicializar el servidor, necesitamos crear un script en el campo scripts del archivo package.json que usará Nodemon para ejecutar el app.js creado. También es importante cambiar el main para el archivo citado. Si todo va bien, cuando ejecutes el comando npm run dev en la terminal de la carpeta raíz de tu proyecto, obtendrás el siguiente resultado:
Configurando la conexión con la base de datos
Para conectar Node.js y MySQL con la biblioteca MySQL2, necesitamos usar algunas características que nos proporciona la herramienta. Primero, crearemos una carpeta llamada connection con un archivo index.js que contendrá la configuración necesaria para la conexión:
Echemos un vistazo más de cerca a las implementaciones realizadas en la Figura 4:
- El uso de promise en la importación de MySQL2 en la línea 1 es necesario porque las consultas a bases de datos externas implican tratamientos por asincronicidad. Por ende, para utilizar async y await con la biblioteca, necesitamos importar de esta forma;
- Utilizamos la función createPool de MySQL2 en la línea 3, responsable de devolver un conjunto de conexiones previas con la base de datos, las cuales serán utilizadas a lo largo de la ejecución de la aplicación para realizar cualquier tipo de interacción con MySQL;
- Dentro de la función createPool informamos el host de nuestra aplicación, el puerto asociado con MySQL, el nombre de la base de datos y el usuario y contraseña de conexión.
Creando rutas
Ahora que estamos listos para crear las primeras interacciones con la base de datos, crearemos una ruta para cada operación CRUD llamada actors. Por razones de organización, deberá crearse dentro de una carpeta llamada routes.
En la ruta creada, importaremos la función Router perteneciente a Express, ejecutando y exportando la misma. También crearemos en nuestro archivo principal app.js la relación entre dicha ruta con el endpoint /actors.
Información importante
Antes de comenzar a cubrir cada operación CRUD específica, debemos aclarar algunas cosas. El primer dato importante es que utilizaremos en este proyecto una base de datos proporcionada por el propio MySQL, llamada sakila. Puedes hacer download del archivo SQL aquí, extraerlo e importarlo en tu MySQL. En esta base de datos, utilizaremos la tabla actor y crearemos un archivo llamado querys donde se harán todas las requisiciones a la base de datos, centrándonos en una mejor organización de nuestro código.
La mayoría de las solicitudes en Internet se realizan mediante el protocolo HTTP. Esto, a su vez, nos proporciona varios métodos (también conocidos como verbos) de solicitudes, que hoy reduciremos a cuatro (uno para cada operación CRUD): POST, GET, PUT y DELETE, respectivamente.
Operaciones CRUD en la práctica
Lectura con el verbo GET
Para mostrar todos los elementos que componen la tabla de actores, recurriremos al método get, utilizado en este caso para mostrar la información que devolverá la consulta a la base de datos.
Centrémonos primero en esta interacción con el banco. Importaremos la connection que creamos y usaremos la función execute, encargada de enviar una consulta MySQL como parámetro:
Nota en la figura 7 que hubo una desestructuración del valor que recibe la consulta de la línea 4. Esto sucede porque la respuesta devuelta por esta query es un array con información variada, donde la primera posición almacena los datos que fueron arrojados con la consulta.
Ahora, necesitamos ejecutar el método get de la función router en la ruta actors. Esta función recibe como parámetros un endpoint y una función que, sucesivamente, recibe la requisición y la respuesta de este endpoint. Dentro de ella ejecutamos la funcióno getAllActors y la retornamos como una respuesta de status 200 y formato json:
También es posible utilizar el método get para retornar un ítem determinado de acuerdo con un parámetro específico, encaminado vía endpoint. Imaginemos que en este endpoint enviaremos un id, siendo el ítem con este id el único que se mostrará. Primero, creamos el parámetro en el endpoint utilizando dos puntos (:), seguido del nombre que le daremos. Este parámetro quedará guardado en params, ubicado dentro de la requisición recibida por el método get.
Creamos una lógica de programación que, en caso de que no se encuentre el id enviado, devolverá el mensaje actor not found. De lo contrario, se retornará el ítem con el id encontrado.
Ahora necesitamos crear una función que reciba el id como parámetro y haga una consulta en la base de datos, devolviendo un ítem que tenga el id igual al recibido:
Creación con el verbo POST
Llegó la hora de crear el método que agrega una nueva persona a la tabla actors. En esta ocasión, utilizaremos el método post, normalmente utilizado para este proceso.
Post es utilizado para envíos de forma más segura que con endpoint, como hicimos en el método get. Supongamos que para hacer una nueva entrada en la tabla de actores necesitamos enviar los datos de nombre y apellido. De esta forma, tendremos la siguiente petición:
Para una mejor comprensión de lo que sucede, imagina que nuestro frontend nos envía los datos de nombre y apellido que serán necesarios para el registro, a través de dos inputs completados por el usuario.
Podemos acceder a lo que reenvía el cuerpo de la solicitud a través del objeto body, al que a su vez accede el método de solicitud. Velo aquí:
Ahora que se creó el método post, vamos a crear la función createActor. Ella precisa recibir los parámetros first_name y last_name para insertarlos en la tabla actor:
Nota que, cuando utilizamos el INSERT de MySQL, el connection que creamos devuelve un resultado diferente al de cuando utilizábamos SELECT:
Este objeto devuelto trae algunos datos importantes, como el número de líneas afectadas con nuestras acciones y el id insertado para el ítem registrado. Siendo así, ¿por qué en lugar de devolver ese objeto no devolvemos el ítem completo registrado, con todas las columnas que posee? Podemos incluso utilizar la función getActorsById para esto:
Ahora tendremos la siguiente respuesta para nuestra requisición:
Actualización con el verbo PUT
Para actualizar un ítem ya existente en la tabla, utilizaremos el método put, que generalmente es utilizado para realizar requisiciones de actualización. Genéricamente hablando, usamos put cuando es necesario enviar una información sin hacer ninguna otra acción aparte de almacenarla. La creación del método no será muy diferente de lo ya hecho anteriormente:
Esta vez, esperamos que se envíen tres campos en el cuerpo de la solicitud: id, first_name y last_name. Lo que haremos en la función de interacción con la base de datos es cambiar los valores de las columnas first_name y last_name en la línea que posea un actor_id igual al id proporcionado.
Nota que primero verificamos si el id ya existía en la tabla, lo cual arrojará null si no era el caso. De esta forma, evitamos un intento de actualización que no surtiría efecto.
Exclusión con el verbo DELETE
Llegamos a la última operación del CRUD. Para realizar la exclusión utilizaremos el verbo DELETE, empleado para requisiciones que tienen como objetivo eliminar alguna información. Para esto, recibiremos un id en el cuerpo de la requisición y lo utilizaremos para excluir la línea de la tabla que posea un actor_id igual al parámetro reenviado:
De la misma forma como hicimos en el método put, primero debemos verificar si existe alguma línea de la tabla que pose el referido id, para ejecutar después solamente el comando de exclusión:
Ejecuta el código a continuación y nota que la aplicación presentará el error que aparece abajo:
“cannot delete or update a parent row: a foreign key constraint fails (`sakila`.`film_actor`, CONSTRAINT `fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES `actor` (`actor_id`) ON DELETE RESTRICT ON UPDATE CASCADE)”
El error sucede porque existe una foreign key en otra tabla de sakila que depende directamente del campo actor_id de la tabla actor. Esta vinculación entre las dos columnas se creó con una restricción que impide que una línea de actor sea borrada sin que pase lo mismo con sus dependientes.
Este error no ocurriría si en el método de creación de la tabla fuese utilizado un ON DELETE CASCADE en lugar de un ON DELETE RESTRICT. Para resolver el problema, basta excluir primero el campo de la tabla film_actor (origen del error, como podemos ver en la descripción), relacionado con el actor_id que queremos excluir:
Consideraciones finales
En este artículo, aprendimos cómo crear, leer, cambiar y eliminar elementos en una base de datos mediante la interacción entre Node.js y MySQL. A partir de los verbos POST, GET, PUT y DELETE, vimos las formas de requisición y las respuestas recibidas para cada uno de los métodos, así como algunas formas de consulta en MySQL para que la interacción se realizara con efectividad.
Espero que hayas aprendido sobre CRUD y que sea útil en tus proyectos. ¡Hasta luego!
Listopro Community da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.