15 - Comunicación con el gestor de base de datos MySQL empleando el módulo 'mysql'


Una actividad muy común de una aplicación web es el acceso a un gestor de base de datos. Veremos en este concepto como podemos comunicarnos desde nuestra aplicación Node.js con el servidor de base de datos MySQL.

Lo primero que debemos tener en cuenta es que tenemos que instalar el gestor de base de datos MySQL. Instalaremos el WampServer y los pasos para dicha actividad los puede leer aquí.

El segundo paso será crear la base de datos que la llamaremos 'base1' y los pasos puede leerlos aquí. No crear tablas ya que nuestra aplicación se encargará de eso.

Problema

Desarrollar una aplicación web que permita administrar una tabla llamada 'articulos' en la base de datos 'base1'. Debemos poder crear la tabla, cargar registros, consultarlos y listarlos.

Como primer paso crearemos una carpeta donde localizaremos nuestro proyecto. Crear una carpeta llamada: ejercicio17. Dentro de esta carpeta crear un archivo 'ejercicio17.js' donde codificaremos la aplicación en Node.js. Por otro lado crear una subcarpeta llamada 'public' y en dicha carpeta guardaremos todas las páginas estáticas de nuestra aplicación.

Como dijimos Node.js deja liberada a la comunidad para implementar módulos para comunicarse con otras aplicaciones. Para comunicarnos con MySQL existe un módulo llamado 'mysql'.

Desde la consola de comando nos posicionamos en la carpeta 'ejercicio17' y procedemos a instalar el módulo 'mysql' mediante 'npm':

modulo mysql de node.js

Ahora tenemos creada una subcarpeta 'node_modules' con una subcarpeta 'mysql' con el módulo propiamente dicho que nos facilitará la comunicación con MySQL.

En la carpeta public localizar los tres archivos HTML estáticos:

modulo mysql de node.js

index.html
<!doctype html>
<html>
<head>
  <title>Prueba</title>
</head>
<body>
   <a href="creartabla">Creacion de una tabla 'articulos' con MySQL</a></p>
   <a href="alta.html">alta de articulos</a></p>
   <a href="listado">Listado completo de articulos</a></p>   
   <a href="consulta.html">Consulta de un articulo por codigo</a></p>      
</body>
</html>
alta.html
<!doctype html>
<html>
<head>
</head>
<body>
  <form method="post" action="alta">
  Ingrese descripcion del articulo:
  <input type="descripcion" name="descripcion" size="50">
  <br>
  Ingrese el precio del articulo:
  <input type="text" name="precio" size="10">
  <br>
  <input type="submit" value="Agregar">
  </form>
</body>
</html>  
consulta.html
  
<!doctype html>
<html>
<head>
</head>
<body>
  <form method="post" action="consultaporcodigo">
  Ingrese el codigo del articulo a consultar:
  <input type="text" name="codigo" size="7">
  <br>
  <input type="submit" value="Consultar">
  </form>
</body>
</html>  

En la carpeta ejercicio17 localizamos el programa en Node.js propiamente dicho:

modulo mysql de node.js

El código fuente en Node.js para crear la tabla, efectuar el alta, listado y consultas es:

ejercicio17.js
const http=require('http');
const url=require('url');
const fs=require('fs');
const querystring = require('querystring');

const mysql=require('mysql');

const conexion=mysql.createConnection({
  host:'localhost',
  user:'root',
  password:'',
  database:'base1'
});

conexion.connect(error => {
  if (error)
    console.log('Problemas de conexion con mysql');
});


const mime = {
   'html' : 'text/html',
   'css'  : 'text/css',
   'jpg'  : 'image/jpg',
   'ico'  : 'image/x-icon',
   'mp3'  : 'audio/mpeg3',
   'mp4'  : 'video/mp4'
};

const servidor=http.createServer((pedido,respuesta) => {
  const objetourl = url.parse(pedido.url);
  let camino='public'+objetourl.pathname;
  if (camino=='public/')
    camino='public/index.html';
  encaminar(pedido,respuesta,camino);
});

servidor.listen(8888);


function encaminar (pedido,respuesta,camino) {
  
  switch (camino) {
    case 'public/creartabla': {
      crear(respuesta);
      break;
    }	
    case 'public/alta': {
      alta(pedido,respuesta);
      break;
    }			
    case 'public/listado': {
      listado(respuesta);
      break;
    }
    case 'public/consultaporcodigo': {
      consulta(pedido,respuesta);
      break;
    }							
      default : {  
        fs.stat(camino, error => {
          if (!error) {
              fs.readFile(camino,(error,contenido) => {
            if (error) {
              respuesta.writeHead(500, {'Content-Type': 'text/plain'});
              respuesta.write('Error interno');
              respuesta.end();					
            } else {
              const vec = camino.split('.');
              const extension=vec[vec.length-1];
              const mimearchivo=mime[extension];
              respuesta.writeHead(200, {'Content-Type': mimearchivo});
              respuesta.write(contenido);
              respuesta.end();
            }
          });
        } else {
          respuesta.writeHead(404, {'Content-Type': 'text/html'});
          respuesta.write('<!doctype html><html><head></head><body>Recurso inexistente</body></html>');		
          respuesta.end();
        }
      });	
    }
  }	
}


function crear(respuesta) {
  conexion.query('drop table if exists articulos', (error,resultado) => {
    if (error)
      console.log(error);				
  });	
  conexion.query(`create table articulos (
                                           codigo int primary key auto_increment,
                                           descripcion varchar(50),
                                           precio float
                                         )`, (error,resultado) => {
    if (error) {
      console.log(error);				
      return;
    }  
  });
  respuesta.writeHead(200, {'Content-Type': 'text/html'});
  respuesta.write(`<!doctype html><html><head></head><body>
                  Se creo la tabla<br><a href="index.html">Retornar</a></body></html>`);		
  respuesta.end();	
}


function alta(pedido,respuesta) {
  let info='';
  pedido.on('data', datosparciales => {
    info += datosparciales;
  });
  pedido.on('end', () => {
    const formulario = querystring.parse(info);
    const registro={
      descripcion:formulario['descripcion'],
      precio:formulario['precio']
    };
    conexion.query('insert into articulos set ?',registro, (error,resultado) => {
      if (error) {
        console.log(error);
        return;
      }	  
    });		
    respuesta.writeHead(200, {'Content-Type': 'text/html'});
    respuesta.write(`<!doctype html><html><head></head><body>
                    Se cargo el articulo<br><a href="index.html">Retornar</a></body></html>`);		
    respuesta.end();
  });  	
}


function listado(respuesta) {
  conexion.query('select codigo,descripcion,precio from articulos', (error,filas) => {
    if (error) {			
      console.log('error en el listado');
      return;
    }
    respuesta.writeHead(200, {'Content-Type': 'text/html'});
    let datos='';
    for(let f=0;f<filas.length;f++){
      datos+='Codigo:'+filas[f].codigo+'<br>';
      datos+='Descripcion:'+filas[f].descripcion+'<br>';
      datos+='Precio:'+filas[f].precio+'<hr>';
    }
    respuesta.write('<!doctype html><html><head></head><body>');
    respuesta.write(datos);	
    respuesta.write('<a href="index.html">Retornar</a>');
    respuesta.write('</body></html>');
    respuesta.end();		
  });
}


function consulta(pedido,respuesta) {
  let info='';
  pedido.on('data', datosparciales => {
    info += datosparciales;
  });
  pedido.on('end', () => {
    const formulario = querystring.parse(info);
    const dato=[formulario['codigo']];
    conexion.query('select descripcion,precio from articulos where codigo=?',dato, (error,filas) => {
      if (error) {			
        console.log('error en la consulta');
        return;
      }
      respuesta.writeHead(200, {'Content-Type': 'text/html'});
      let datos='';
      if (filas.length>0) {
        datos+='Descripcion:'+filas[0].descripcion+'<br>';
        datos+='Precio:'+filas[0].precio+'<hr>';
      } else {
        datos='No existe un artículo con dicho codigo.';
      }	
      respuesta.write('<!doctype html><html><head></head><body>');
      respuesta.write(datos);	
        respuesta.write('<a href="index.html">Retornar</a>');			
      respuesta.write('</body></html>');
      respuesta.end();		
    });
  });  	 
}

console.log('Servidor web iniciado');

Iremos viendo por partes las distintas funcionalidades que tiene el programa para manipular una base de datos de MySQL.

Lo primero que hacemos es requerir el módulo 'mysql' mediante la función require:

const mysql=require('mysql');

Mediante la constante mysql llamamos a la función createConnection y le pasamos un objeto literal inicializando las propiedades 'host','user','password' y 'database'. Como dijimos ya creamos desde el PhpMyAdmin la base de datos 'base1':

var conexion=mysql.createConnection({
    host:'localhost',
    user:'root',
    password:'',
    database:'base1'
});

Con la referencia a la conexión procedemos a llamar a connect para abrir la conexión con el servidor de base de datos (si hay algún error la función anónima traerá una referencia de dicho error):

conexion.connect(error => {
  if (error)
    console.log('Problemas de conexion con mysql');
});

Arranquemos nuestro programa desde la consola y desde el munú de opciones en el navegador elijamos la primer opción:

c:\ejerciciosnodejs\ejercicio17\node ejercicio17

modulo mysql de node.js

Tenemos en el hipervínculo que la propiedad href tiene el valor 'creartabla':

   <a href="creartabla">Creacion de una tabla 'articulos' con MySQL</a></p>

Desde Node.js capturamos la ruta indicada en el hipervínculo:

        case 'public/creartabla': {
            crear(respuesta);
            break;
        }    

En la función crear llamamos a la función query del objeto conexion que creamos previamente:

function crear(respuesta) {
  conexion.query('drop table if exists articulos', (error,resultado) => {
    if (error)
      console.log(error);				
  });	
  conexion.query(`create table articulos (
                                           codigo int primary key auto_increment,
                                           descripcion varchar(50),
                                           precio float
                                         )`, (error,resultado) => {
    if (error) {
      console.log(error);				
      return;
    }  
  });
  respuesta.writeHead(200, {'Content-Type': 'text/html'});
  respuesta.write(`<!doctype html><html><head></head><body>
                  Se creo la tabla<br><a href="index.html">Retornar</a></body></html>`);		
  respuesta.end();	
}

En la primer llamada de la función query le pasamos el comando SQL 'drop table if exists articulos' para que si ya existía la tabla proceda a borrarla.

En la segunda llamada a query le pasamos el comando SQL 'create table articulos ...' para que se cree la tabla.

Siempre que llamamos a query debemos pasarle además del string con el comando SQL un segundo parámetro que se trata de una función anónima que nos retorna un eventual error y los resultados que genera el comando SQL ejecutado.

Una vez que ejecutamos la primer opción ya tenemos creada la tabla. Pasemos a ver como funciona el alta en la tabla articulos. Cuando seleccionamos la segunda opción de la página index.html se solicita la página estática alta.html:

   <a href="alta.html">alta de articulos</a></p>

El servidor implementado con Node.js devuelve dicha página al navegador que la solicita, donde el operador procede a cargar datos:

modulo mysql de node.js

Cuando se presiona el botón 'Agregar' vemos que la propiedad action del formulario tiene el valor 'alta':

  <form method="post" action="alta">

Este valor lo capturamos desde nuestro programa de Node.js:

        case 'public/alta': {
            alta(pedido,respuesta);
            break;
        }            

La función alta:

function alta(pedido,respuesta) {
  let info='';
  pedido.on('data', datosparciales => {
       info += datosparciales;
  });
  pedido.on('end', () => {
    const formulario = querystring.parse(info);
    const registro={
     descripcion:formulario['descripcion'],
     precio:formulario['precio']
    };
    conexion.query('insert into articulos set ?',registro, (error,resultado) => {
      if (error) {
        console.log(error);
        return;
      }	  
    });		
    respuesta.writeHead(200, {'Content-Type': 'text/html'});
    respuesta.write(`<!doctype html><html><head></head><body>
                    Se cargo el articulo<br><a href="index.html">Retornar</a></body></html>`);		
    respuesta.end();
  });  	
}

Procede a rescatar todos los datos del formulario y a llamar a la función query de la variable conexion pasando el string con el comando SQL. El segundo parámetro de la función es un objeto literal donde inicializamos todos los campos de la tabla (menos el código de artículo ya que se genera automáticamente).

Si bien en SQL no existe la palabra clave set tengamos en cuenta que la función query procederá a generar un comando insert válido.

Nuevamente vemos que el tercer parámetro es la función anónima que se dispara luego que se ejecutó el comando SQL.

Finalmente respondemos al navegador con una página que generamos en forma dinámica.

El listado completo lo llamamos desde la página index.html:

   <a href="listado">Listado completo de articulos</a></p> 

Desde Node.js capturamos la url que llega con el valor 'listado':

        case 'public/listado': {
            listado(respuesta);
            break;
        }

En la función listado procedemos a mostrar todos los datos de la tabla 'articulos':

function listado(respuesta) {
  conexion.query('select codigo,descripcion,precio from articulos', (error,filas) => {
    if (error) {			
      console.log('error en el listado');
      return;
    }
    respuesta.writeHead(200, {'Content-Type': 'text/html'});
    let datos='';
    for(let f=0;f<filas.length;f++){
      datos+='Codigo:'+filas[f].codigo+'<br>';
      datos+='Descripcion:'+filas[f].descripcion+'<br>';
      datos+='Precio:'+filas[f].precio+'<hr>';
    }
    respuesta.write('<!doctype html><html><head></head><body>');
    respuesta.write(datos);	
    respuesta.write('<a href="index.html">Retornar</a>');
    respuesta.write('</body></html>');
    respuesta.end();		
  });
}

En este algoritmos es muy importante lo que hacemos en la función anónima donde procedemos a mostrar todos los datos en la página HTML que generamos en forma dinámica:

modulo mysql de node.js

Lo único que nos queda es la consulta por el código. Desde la página index.html procedemos a solicitar la página estática consulta.html:

   <a href="consulta.html">Consulta de un articulo por codigo</a></p>      

Esta página estática solicita que se ingrese el código de artículo y procede a enviarlo al servidor indicando en la propiedad action del elemento 'form' el valor 'consultaporcodigo':

  <form method="post" action="consultaporcodigo">

En Node.js capturamos este valor:

        case 'public/consultaporcodigo': {
            consulta(pedido,respuesta);
            break;
        }                            

Y llamamos a la función consulta donde rescatamos los valores del formulario y procedemos a llamar al comando SQL select con la clausula where indicando el código que cargó el operador en el formulario HTML:

function consulta(pedido,respuesta) {
  let info='';
  pedido.on('data', datosparciales => {
    info += datosparciales;
  });
  pedido.on('end', () => {
    const formulario = querystring.parse(info);
    const dato=[formulario['codigo']];
    conexion.query('select descripcion,precio from articulos where codigo=?',dato, (error,filas) => {
      if (error) {			
        console.log('error en la consulta');
        return;
      }
      respuesta.writeHead(200, {'Content-Type': 'text/html'});
      let datos='';
      if (filas.length>0) {
        datos+='Descripcion:'+filas[0].descripcion+'<br>';
        datos+='Precio:'+filas[0].precio+'<hr>';
      } else {
        datos='No existe un artículo con dicho codigo.';
      }	
      respuesta.write('<!doctype html><html><head></head><body>');
      respuesta.write(datos);	
        respuesta.write('<a href="index.html">Retornar</a>');			
      respuesta.write('</body></html>');
      respuesta.end();		
    });
  });  	 
}

Este proyecto lo puede descargar en un zip con todos los archivos desde este enlace : ejercicio17

Es importante conocer y visitar el sitio oficial de cada módulo que implementan los desarrolladores donde podemos enterarnos de las mejoras que le añaden. El sitio oficial de la extensión 'mysql' lo puede visitar aquí

Retornar