Lab 17: Interacción con la base de datos
Descripción
En esta actividad comenzaremos con la interacción con una base de datos desde node.
Modalidad
Individual.
Objetivos de aprendizaje
- Entender cómo interactúa una aplicación web con una base de datos.
- Desarrollar aplicaciones web que interactúen con bases de datos.
Instrucciones
- Para interactuar con una base de datos, debemos crear la base de datos. Para este laboratorio usaremos MySQL, sin embargo, la lógica es muy similar si decides trabajar con cualquier otro motor de bases de datos. Crea tu base de datos y crea algunas tablas y ponles algunos datos, de manera similar a la demostración del profesor.
- Para poder interactuar con el manejador de base de datos MySQL, ocuparemos el paquete
mysql2
. - Para poder conectarnos con la base de datos, utilizaremos el archivo
database.js
, el cual crearemos dentro de un folder con nuestras librerías de apoyo, típicamente nombradoutil
. El archivo se encargará de manejar las conexiones con nuestra base de datos:
Asegúrate de cambiar los valores de los atributos del objeto de js para que coincidan con los de tu base de datos. Como podrás observar, se exporta una promesa. Las promesas permiten manejar fácilmente código que se ejecuta de manera asíncrona.const mysql = require('mysql2'); const pool = mysql.createPool({ host: 'localhost', user: 'root', database: 'database_name', password: 'el_password_de_tu_usuario_de_la_bd' }); module.exports = pool.promise();
- Para conectarnos con la base de datos y ejecutar consultas desde nuestra aplicación:
Ahora, debido a que enconst db = require('./util/database'); db.execute('Consulta SQL por ejemplo: SELECT * FROM mi_tabla');
database.js
devolvimos una promesa, esto nos permite hacer algo después de que ejecutamos la consulta con el método.then()
, e incluso manejar los errores con el método.catch()
. Por ejemplo, si queremos recuperar los registros de la tabla mascotas:
En la varibaledb.execute('SELECT * FROM mascotas') .then(([rows, fieldData]) => { console.log(rows); }) .catch(err => { console.log(err); });
rows
, tendremos cada uno de de los registros de nuestra consulta. - El código de interacción con la base de datos, si seguimos buenas prácticas, lo escribiremos siempre en nuestros modelos. Por lo que normalmente, el método
fetchAll()
de nuestros modelos quedaría con el siguiente formato:
Y el código del controlador (asumiendo que tenemos un template de la vista llamado 'vista.html' que despliega el contenido de un arreglo de js llamado mascotas):static fetchAll() { return db.execute('SELECT * FROM mascotas'); }
exports.getMascotas = (request, response, next) => { Mascota.fetchAll() .then(([rows, fieldData]) => { response.render('vista', { mascotas: rows }) }) .catch(err => console.log(err)); }
-
Ahora, para insertar un registro en la base de datos, nuestro código del método
save()
en los modelos, tendría el siguiente formato:
Como podrás ver, no se insertan los valores directamente en el string, sino se pone un signo de interrogación, esto es para evitar ataques de inyección de SQL, ya que el método execute, al pasar estos datos en un arreglo como segundo argumento, evita que si se inserta código SQL, éste no se ejecute y simplemente sea interpretado como un string.save() { return db.execute('INSERT INTO mascotas (nombre_columna_1, nombre_columna_2) VALUES (?, ?)', [this.variable_valor_1, this.variable_valor_2] ); }
El código del controlador quedaría con el siguiente formato:exports.insertarMascota = (request, response, next) => { const mascota = new Mascota(request.body.nombre, request.body.descripcion); mascota.save().then(() => { response.redirect('/'); }).catch(err => console.log(err)); };
- En ocasiones es necesario recuperar un registro en particular de la base de datos, y muchas veces queremos que esto pueda realizarse desde las rutas. Para indicarle al ruteador de express que un valor en una ruta es una varibale, podemos hacerlo agregando como prefijo el símbolo
:
seguido del nombre que le queremos dar a la variable:
Y en el controlador para hacer uso de la variable:router.get('/mascotas/:mascota_id', controllerMascotas.getMascota);
export.getMascota = (request, response, next) => { const id = request.params.mascota_id; //Resto del código del controlador... }
- Continúa mejorando tus laboratorios anteriores o tu proyecto agregándoles interacción con la base de datos. Asegúrate de al menos realizar una consulta que devuelva varios registros, una consulta que devuelva 1 sólo registro, una inserción, y una edición de un registro de la base de datos. Recuerda que siempre tienes también la opción de crear una nueva aplicación.
Preguntas a responder
- ¿Qué ventajas tiene escribir el código SQL únicamente en la capa del modelo?
- ¿Qué es SQL injection y cómo se puede prevenir?
Recursos
Especificaciones de entrega
A través de tu repositorio personal (Bitbucket o GitHub).